diff --git a/Book-Lite/code-list/html/P12-1.html b/Book-Lite/code-list/html/P12-1.html index c0e53d8..76b1d6e 100644 --- a/Book-Lite/code-list/html/P12-1.html +++ b/Book-Lite/code-list/html/P12-1.html @@ -11,24 +11,24 @@ {font-family:Wingdings; panose-1:5 0 0 0 0 0 0 0 0 0;} @font-face - {font-family:����; + {font-family:宋体; panose-1:2 1 6 0 3 1 1 1 1 1;} @font-face - {font-family:����; + {font-family:黑体; panose-1:2 1 6 9 6 1 1 1 1 1;} @font-face - {font-family:����; + {font-family:黑体; panose-1:2 1 6 9 6 1 1 1 1 1;} @font-face - {font-family:����С���μ���;} + {font-family:方正小标宋简体;} @font-face - {font-family:"\@����"; + {font-family:"\@黑体"; panose-1:2 1 6 9 6 1 1 1 1 1;} @font-face - {font-family:"\@����"; + {font-family:"\@宋体"; panose-1:2 1 6 0 3 1 1 1 1 1;} @font-face - {font-family:"\@����С���μ���";} + {font-family:"\@方正小标宋简体";} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {margin:0cm; @@ -36,9 +36,9 @@ text-align:justify; text-justify:inter-ideograph; font-size:10.5pt; - font-family:����;} + font-family:宋体;} h1 - {mso-style-link:"���� 1 Char"; + {mso-style-link:"标题 1 Char"; margin-top:17.0pt; margin-right:0cm; margin-bottom:16.5pt; @@ -47,10 +47,10 @@ h1 text-indent:-7.2pt; page-break-after:avoid; font-size:22.0pt; - font-family:����; + font-family:宋体; font-weight:bold;} h2 - {mso-style-link:"���� 2 Char"; + {mso-style-link:"标题 2 Char"; margin-top:13.0pt; margin-right:0cm; margin-bottom:13.0pt; @@ -63,7 +63,7 @@ h2 font-family:"Arial","sans-serif"; font-weight:bold;} h3 - {mso-style-link:"���� 3 Char"; + {mso-style-link:"标题 3 Char"; margin:0cm; margin-bottom:.0001pt; text-align:justify; @@ -74,7 +74,7 @@ h3 font-family:"Arial","sans-serif"; font-weight:bold;} h4 - {mso-style-link:"���� 4 Char"; + {mso-style-link:"标题 4 Char"; margin-top:0cm; margin-right:0cm; margin-bottom:0cm; @@ -88,7 +88,7 @@ h4 font-family:"Arial","sans-serif"; font-weight:bold;} h5 - {mso-style-link:"���� 5 Char"; + {mso-style-link:"标题 5 Char"; margin-top:14.0pt; margin-right:0cm; margin-bottom:14.5pt; @@ -99,10 +99,10 @@ h5 line-height:156%; page-break-after:avoid; font-size:14.0pt; - font-family:����; + font-family:宋体; font-weight:bold;} h6 - {mso-style-link:"���� 6 Char"; + {mso-style-link:"标题 6 Char"; margin-top:12.0pt; margin-right:0cm; margin-bottom:3.2pt; @@ -116,7 +116,7 @@ h6 font-family:"Arial","sans-serif"; font-weight:bold;} p.MsoHeading7, li.MsoHeading7, div.MsoHeading7 - {mso-style-link:"���� 7 Char"; + {mso-style-link:"标题 7 Char"; margin-top:12.0pt; margin-right:0cm; margin-bottom:3.2pt; @@ -127,10 +127,10 @@ p.MsoHeading7, li.MsoHeading7, div.MsoHeading7 line-height:133%; page-break-after:avoid; font-size:12.0pt; - font-family:����; + font-family:宋体; font-weight:bold;} p.MsoHeading8, li.MsoHeading8, div.MsoHeading8 - {mso-style-link:"���� 8 Char"; + {mso-style-link:"标题 8 Char"; margin-top:12.0pt; margin-right:0cm; margin-bottom:3.2pt; @@ -143,7 +143,7 @@ p.MsoHeading8, li.MsoHeading8, div.MsoHeading8 font-size:12.0pt; font-family:"Arial","sans-serif";} p.MsoHeading9, li.MsoHeading9, div.MsoHeading9 - {mso-style-link:"���� 9 Char"; + {mso-style-link:"标题 9 Char"; margin-top:12.0pt; margin-right:0cm; margin-bottom:3.2pt; @@ -165,7 +165,7 @@ p.MsoIndex1, li.MsoIndex1, div.MsoIndex1 text-justify:inter-ideograph; text-indent:-10.5pt; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.MsoIndex2, li.MsoIndex2, div.MsoIndex2 {margin-top:0cm; margin-right:0cm; @@ -176,7 +176,7 @@ p.MsoIndex2, li.MsoIndex2, div.MsoIndex2 text-justify:inter-ideograph; text-indent:-10.5pt; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.MsoIndex3, li.MsoIndex3, div.MsoIndex3 {margin-top:0cm; margin-right:0cm; @@ -187,7 +187,7 @@ p.MsoIndex3, li.MsoIndex3, div.MsoIndex3 text-justify:inter-ideograph; text-indent:-10.5pt; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.MsoIndex4, li.MsoIndex4, div.MsoIndex4 {margin-top:0cm; margin-right:0cm; @@ -198,7 +198,7 @@ p.MsoIndex4, li.MsoIndex4, div.MsoIndex4 text-justify:inter-ideograph; text-indent:-10.5pt; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.MsoIndex5, li.MsoIndex5, div.MsoIndex5 {margin-top:0cm; margin-right:0cm; @@ -209,7 +209,7 @@ p.MsoIndex5, li.MsoIndex5, div.MsoIndex5 text-justify:inter-ideograph; text-indent:-10.5pt; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.MsoIndex6, li.MsoIndex6, div.MsoIndex6 {margin-top:0cm; margin-right:0cm; @@ -220,7 +220,7 @@ p.MsoIndex6, li.MsoIndex6, div.MsoIndex6 text-justify:inter-ideograph; text-indent:-10.5pt; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.MsoIndex7, li.MsoIndex7, div.MsoIndex7 {margin-top:0cm; margin-right:0cm; @@ -231,7 +231,7 @@ p.MsoIndex7, li.MsoIndex7, div.MsoIndex7 text-justify:inter-ideograph; text-indent:-10.5pt; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.MsoIndex8, li.MsoIndex8, div.MsoIndex8 {margin-top:0cm; margin-right:0cm; @@ -242,7 +242,7 @@ p.MsoIndex8, li.MsoIndex8, div.MsoIndex8 text-justify:inter-ideograph; text-indent:-10.5pt; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.MsoIndex9, li.MsoIndex9, div.MsoIndex9 {margin-top:0cm; margin-right:0cm; @@ -253,14 +253,14 @@ p.MsoIndex9, li.MsoIndex9, div.MsoIndex9 text-justify:inter-ideograph; text-indent:-10.5pt; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.MsoToc1, li.MsoToc1, div.MsoToc1 {margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; font-size:10.5pt; - font-family:����; + font-family:宋体; font-weight:bold;} p.MsoToc2, li.MsoToc2, div.MsoToc2 {margin-top:0cm; @@ -271,7 +271,7 @@ p.MsoToc2, li.MsoToc2, div.MsoToc2 text-align:justify; text-justify:inter-ideograph; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.MsoToc3, li.MsoToc3, div.MsoToc3 {margin-top:0cm; margin-right:0cm; @@ -281,7 +281,7 @@ p.MsoToc3, li.MsoToc3, div.MsoToc3 text-align:justify; text-justify:inter-ideograph; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.MsoToc4, li.MsoToc4, div.MsoToc4 {margin-top:0cm; margin-right:0cm; @@ -289,7 +289,7 @@ p.MsoToc4, li.MsoToc4, div.MsoToc4 margin-left:31.5pt; margin-bottom:.0001pt; font-size:9.0pt; - font-family:����;} + font-family:宋体;} p.MsoToc5, li.MsoToc5, div.MsoToc5 {margin-top:0cm; margin-right:0cm; @@ -297,7 +297,7 @@ p.MsoToc5, li.MsoToc5, div.MsoToc5 margin-left:42.0pt; margin-bottom:.0001pt; font-size:9.0pt; - font-family:����;} + font-family:宋体;} p.MsoToc6, li.MsoToc6, div.MsoToc6 {margin-top:0cm; margin-right:0cm; @@ -305,7 +305,7 @@ p.MsoToc6, li.MsoToc6, div.MsoToc6 margin-left:52.5pt; margin-bottom:.0001pt; font-size:9.0pt; - font-family:����;} + font-family:宋体;} p.MsoToc7, li.MsoToc7, div.MsoToc7 {margin-top:0cm; margin-right:0cm; @@ -313,7 +313,7 @@ p.MsoToc7, li.MsoToc7, div.MsoToc7 margin-left:63.0pt; margin-bottom:.0001pt; font-size:9.0pt; - font-family:����;} + font-family:宋体;} p.MsoToc8, li.MsoToc8, div.MsoToc8 {margin-top:0cm; margin-right:0cm; @@ -321,7 +321,7 @@ p.MsoToc8, li.MsoToc8, div.MsoToc8 margin-left:73.5pt; margin-bottom:.0001pt; font-size:9.0pt; - font-family:����;} + font-family:宋体;} p.MsoToc9, li.MsoToc9, div.MsoToc9 {margin-top:0cm; margin-right:0cm; @@ -329,22 +329,22 @@ p.MsoToc9, li.MsoToc9, div.MsoToc9 margin-left:84.0pt; margin-bottom:.0001pt; font-size:9.0pt; - font-family:����;} + font-family:宋体;} p.MsoFootnoteText, li.MsoFootnoteText, div.MsoFootnoteText - {mso-style-link:"��ע�ı� Char"; + {mso-style-link:"脚注文本 Char"; margin:0cm; margin-bottom:.0001pt; layout-grid-mode:char; font-size:9.0pt; - font-family:����;} + font-family:宋体;} p.MsoCommentText, li.MsoCommentText, div.MsoCommentText - {mso-style-link:"��ע���� Char"; + {mso-style-link:"批注文字 Char"; margin:0cm; margin-bottom:.0001pt; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.MsoHeader, li.MsoHeader, div.MsoHeader - {mso-style-link:"ҳü Char"; + {mso-style-link:"页眉 Char"; margin:0cm; margin-bottom:.0001pt; text-align:center; @@ -352,22 +352,22 @@ p.MsoHeader, li.MsoHeader, div.MsoHeader border:none; padding:0cm; font-size:9.0pt; - font-family:����;} + font-family:宋体;} p.MsoFooter, li.MsoFooter, div.MsoFooter - {mso-style-link:"ҳ�� Char"; + {mso-style-link:"页脚 Char"; margin:0cm; margin-bottom:.0001pt; layout-grid-mode:char; font-size:9.0pt; - font-family:����;} + font-family:宋体;} p.MsoIndexHeading, li.MsoIndexHeading, div.MsoIndexHeading - {mso-style-name:"��������\,������Ŀ\,������Ŀ1\,������Ŀ2"; + {mso-style-name:"索引标题\,索引类目\,索引类目1\,索引类目2"; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.MsoCaption, li.MsoCaption, div.MsoCaption {margin:0cm; margin-bottom:.0001pt; @@ -385,7 +385,7 @@ p.MsoTof, li.MsoTof, div.MsoTof text-justify:inter-ideograph; text-indent:-21.0pt; font-size:10.5pt; - font-family:����;} + font-family:宋体;} span.MsoFootnoteReference {vertical-align:super;} p.MsoList, li.MsoList, div.MsoList @@ -397,22 +397,22 @@ p.MsoList, li.MsoList, div.MsoList text-align:center; text-indent:-21.0pt; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.MsoList2, li.MsoList2, div.MsoList2 {margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.MsoList4, li.MsoList4, div.MsoList4 {margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.MsoDate, li.MsoDate, div.MsoDate - {mso-style-link:"���� Char"; + {mso-style-link:"日期 Char"; margin-top:0cm; margin-right:0cm; margin-bottom:0cm; @@ -421,46 +421,46 @@ p.MsoDate, li.MsoDate, div.MsoDate text-align:justify; text-justify:inter-ideograph; font-size:10.5pt; - font-family:����;} + font-family:宋体;} a:link, span.MsoHyperlink - {mso-style-name:"������\,��������"; + {mso-style-name:"超链接\,超级链接"; color:blue; text-decoration:underline;} a:visited, span.MsoHyperlinkFollowed {color:purple; text-decoration:underline;} p - {mso-style-name:"��ͨ\(��վ\)\,��ͨ \(Web\)\,��ͨ \(Web\)1\,��ͨ \(Web\)2\,��ͨ \(Web\)3"; + {mso-style-name:"普通\(网站\)\,普通 \(Web\)\,普通 \(Web\)1\,普通 \(Web\)2\,普通 \(Web\)3"; margin-right:0cm; margin-left:0cm; font-size:12.0pt; - font-family:����;} + font-family:宋体;} pre - {mso-style-name:"HTML Ԥ���ʽ\,HTML Ԥ�ȸ�ʽ��\,HTML Ԥ�ȸ�ʽ��1\,HTML Ԥ�ȸ�ʽ��2\,HTML Ԥ�ȸ�ʽ��3"; - mso-style-link:"HTML Ԥ���ʽ Char\,HTML Ԥ�ȸ�ʽ�� Char\,HTML Ԥ�ȸ�ʽ��1 Char\,HTML Ԥ�ȸ�ʽ��2 Char\,HTML Ԥ�ȸ�ʽ��3 Char"; + {mso-style-name:"HTML 预设格式\,HTML 预先格式化\,HTML 预先格式化1\,HTML 预先格式化2\,HTML 预先格式化3"; + mso-style-link:"HTML 预设格式 Char\,HTML 预先格式化 Char\,HTML 预先格式化1 Char\,HTML 预先格式化2 Char\,HTML 预先格式化3 Char"; margin:0cm; margin-bottom:.0001pt; font-size:12.0pt; - font-family:����;} + font-family:宋体;} tt - {font-family:����;} + {font-family:黑体;} p.MsoCommentSubject, li.MsoCommentSubject, div.MsoCommentSubject - {mso-style-link:"��ע���� Char"; + {mso-style-link:"批注主题 Char"; margin:0cm; margin-bottom:.0001pt; font-size:10.5pt; - font-family:����; + font-family:宋体; font-weight:bold;} p.MsoAcetate, li.MsoAcetate, div.MsoAcetate - {mso-style-link:"��ע���ı� Char"; + {mso-style-link:"批注框文本 Char"; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; font-size:9.0pt; - font-family:����;} + font-family:宋体;} p.1, li.1, div.1 - {mso-style-name:��ʽ1; + {mso-style-name:样式1; margin-top:0cm; margin-right:0cm; margin-bottom:0cm; @@ -469,213 +469,213 @@ p.1, li.1, div.1 text-align:center; text-indent:-21.0pt; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.a, li.a, div.a - {mso-style-name:�������; - mso-style-link:"������� Char"; + {mso-style-name:代码程序; + mso-style-link:"代码程序 Char"; margin:0cm; margin-bottom:.0001pt; font-size:10.0pt; - font-family:����;} + font-family:宋体;} span.Char - {mso-style-name:"������� Char"; - mso-style-link:�������; - font-family:����;} + {mso-style-name:"代码程序 Char"; + mso-style-link:代码程序; + font-family:宋体;} p.a0, li.a0, div.a0 - {mso-style-name:ͼ˵��; - mso-style-link:"ͼ˵�� Char"; + {mso-style-name:图说明; + mso-style-link:"图说明 Char"; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} span.Char0 - {mso-style-name:"ͼ˵�� Char"; - mso-style-link:ͼ˵��; - font-family:����;} + {mso-style-name:"图说明 Char"; + mso-style-link:图说明; + font-family:宋体;} p.0, li.0, div.0 - {mso-style-name:����0; + {mso-style-name:封面0; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:36.0pt; - font-family:����; + font-family:宋体; font-weight:bold;} p.10, li.10, div.10 - {mso-style-name:����1; + {mso-style-name:封面1; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:18.0pt; - font-family:����; + font-family:宋体; font-weight:bold;} p.11, li.11, div.11 - {mso-style-name:�DZ���1; + {mso-style-name:非标题1; margin-top:7.8pt; margin-right:0cm; margin-bottom:7.8pt; margin-left:0cm; text-align:center; font-size:22.0pt; - font-family:����; + font-family:宋体; font-weight:bold;} p.a1, li.a1, div.a1 - {mso-style-name:�ı�����; + {mso-style-name:文本居中; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.3CharChar, li.3CharChar, div.3CharChar - {mso-style-name:"ͼ������3 Char Char"; - mso-style-link:"ͼ������3 Char Char Char"; + {mso-style-name:"图中文字3 Char Char"; + mso-style-link:"图中文字3 Char Char Char"; margin:0cm; margin-bottom:.0001pt; text-align:center; line-height:9.0pt; font-size:8.0pt; - font-family:����;} + font-family:宋体;} span.3CharCharChar - {mso-style-name:"ͼ������3 Char Char Char"; - mso-style-link:"ͼ������3 Char Char"; - font-family:����;} + {mso-style-name:"图中文字3 Char Char Char"; + mso-style-link:"图中文字3 Char Char"; + font-family:宋体;} p.post, li.post, div.post - {mso-style-name:�ʼ�post; + {mso-style-name:邮件post; margin:0cm; margin-bottom:.0001pt; text-align:right; line-height:11.0pt; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.3, li.3, div.3 - {mso-style-name:ͼ������3; + {mso-style-name:图中字体3; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; font-size:10.5pt; - font-family:����;} + font-family:宋体;} span.3CharChar1CharCharChar - {mso-style-name:"ͼ������3 Char Char1 Char Char Char"; - font-family:����;} + {mso-style-name:"图中文字3 Char Char1 Char Char Char"; + font-family:宋体;} span.3CharChar1CharChar - {mso-style-name:"ͼ������3 Char Char1 Char Char"; - font-family:����;} + {mso-style-name:"图中文字3 Char Char1 Char Char"; + font-family:宋体;} p.5Char, li.5Char, div.5Char - {mso-style-name:"ͼ������5�� Char"; - mso-style-link:"ͼ������5�� Char Char"; + {mso-style-name:"图中文字5号 Char"; + mso-style-link:"图中文字5号 Char Char"; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} span.5CharChar - {mso-style-name:"ͼ������5�� Char Char"; - mso-style-link:"ͼ������5�� Char"; - font-family:����;} + {mso-style-name:"图中文字5号 Char Char"; + mso-style-link:"图中文字5号 Char"; + font-family:宋体;} p.5CharChar0, li.5CharChar0, div.5CharChar0 - {mso-style-name:"ͼ������С5�� Char Char"; - mso-style-link:"ͼ������С5�� Char Char Char"; + {mso-style-name:"图中文字小5号 Char Char"; + mso-style-link:"图中文字小5号 Char Char Char"; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:9.0pt; - font-family:����;} + font-family:宋体;} span.5CharCharChar - {mso-style-name:"ͼ������С5�� Char Char Char"; - mso-style-link:"ͼ������С5�� Char Char"; - font-family:����;} + {mso-style-name:"图中文字小5号 Char Char Char"; + mso-style-link:"图中文字小5号 Char Char"; + font-family:宋体;} p.5Char0, li.5Char0, div.5Char0 - {mso-style-name:"ͼ������С5�� Char"; + {mso-style-name:"图中文字小5号 Char"; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:9.0pt; - font-family:����;} + font-family:宋体;} p.5, li.5, div.5 - {mso-style-name:ͼ������С5��; + {mso-style-name:图中文字小5号; margin:0cm; margin-bottom:.0001pt; text-align:center; layout-grid-mode:char; font-size:9.0pt; - font-family:����;} + font-family:宋体;} p.2, li.2, div.2 - {mso-style-name:�������2; + {mso-style-name:代码程序2; margin:0cm; margin-bottom:.0001pt; font-size:10.0pt; - font-family:����;} + font-family:宋体;} p.20, li.20, div.20 - {mso-style-name:ͼ˵��2; + {mso-style-name:图说明2; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.21, li.21, div.21 - {mso-style-name:�ı�����2; + {mso-style-name:文本居中2; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.3CharCharCharCharChar, li.3CharCharCharCharChar, div.3CharCharCharCharChar - {mso-style-name:"ͼ������3 Char Char Char Char Char"; - mso-style-link:"ͼ������3 Char Char Char Char Char Char"; + {mso-style-name:"图中文字3 Char Char Char Char Char"; + mso-style-link:"图中文字3 Char Char Char Char Char Char"; margin:0cm; margin-bottom:.0001pt; text-align:center; line-height:9.0pt; font-size:8.0pt; - font-family:����;} + font-family:宋体;} span.3CharCharCharCharCharChar - {mso-style-name:"ͼ������3 Char Char Char Char Char Char"; - mso-style-link:"ͼ������3 Char Char Char Char Char"; - font-family:����;} + {mso-style-name:"图中文字3 Char Char Char Char Char Char"; + mso-style-link:"图中文字3 Char Char Char Char Char"; + font-family:宋体;} p.a2, li.a2, div.a2 - {mso-style-name:ͼ����; + {mso-style-name:图居中; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.110, li.110, div.110 - {mso-style-name:"��ʽ ���� 1 + ����1"; + {mso-style-name:"样式 标题 1 + 居中1"; margin-right:0cm; margin-left:0cm; text-align:center; page-break-after:avoid; font-size:22.0pt; - font-family:����; + font-family:宋体; font-weight:bold;} span.1Char - {mso-style-name:"���� 1 Char"; - mso-style-link:"���� 1"; + {mso-style-name:"标题 1 Char"; + mso-style-link:"标题 1"; font-weight:bold;} p.22, li.22, div.22 - {mso-style-name:"��ʽ �б� 2 + ����"; + {mso-style-name:"样式 列表 2 + 居中"; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.23, li.23, div.23 - {mso-style-name:�б�2; + {mso-style-name:列表2; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.50, li.50, div.50 - {mso-style-name:ͼ������5��; + {mso-style-name:图中文字5号; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.111, li.111, div.111 - {mso-style-name:��ʽ11; + {mso-style-name:样式11; margin-top:0cm; margin-right:0cm; margin-bottom:0cm; @@ -684,107 +684,107 @@ p.111, li.111, div.111 text-align:center; text-indent:-21.0pt; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.12, li.12, div.12 - {mso-style-name:�������1; + {mso-style-name:代码程序1; margin:0cm; margin-bottom:.0001pt; font-size:10.0pt; - font-family:����;} + font-family:宋体;} p.13, li.13, div.13 - {mso-style-name:ͼ˵��1; + {mso-style-name:图说明1; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.01, li.01, div.01 - {mso-style-name:����01; + {mso-style-name:封面01; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:36.0pt; - font-family:����; + font-family:宋体; font-weight:bold;} p.112, li.112, div.112 - {mso-style-name:����11; + {mso-style-name:封面11; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:18.0pt; - font-family:����; + font-family:宋体; font-weight:bold;} p.113, li.113, div.113 - {mso-style-name:�DZ���11; + {mso-style-name:非标题11; margin-top:7.8pt; margin-right:0cm; margin-bottom:7.8pt; margin-left:0cm; text-align:center; font-size:22.0pt; - font-family:����; + font-family:宋体; font-weight:bold;} p.14, li.14, div.14 - {mso-style-name:�ı�����1; + {mso-style-name:文本居中1; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.3Char1, li.3Char1, div.3Char1 - {mso-style-name:"ͼ������3 Char1"; + {mso-style-name:"图中文字3 Char1"; margin:0cm; margin-bottom:.0001pt; text-align:center; line-height:9.0pt; font-size:8.0pt; - font-family:����;} + font-family:宋体;} p.post1, li.post1, div.post1 - {mso-style-name:�ʼ�post1; + {mso-style-name:邮件post1; margin:0cm; margin-bottom:.0001pt; text-align:right; line-height:11.0pt; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.31, li.31, div.31 - {mso-style-name:ͼ������31; + {mso-style-name:图中字体31; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.5Char1, li.5Char1, div.5Char1 - {mso-style-name:"ͼ������5�� Char1"; + {mso-style-name:"图中文字5号 Char1"; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.5CharChar1, li.5CharChar1, div.5CharChar1 - {mso-style-name:"ͼ������С5�� Char Char1"; + {mso-style-name:"图中文字小5号 Char Char1"; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:9.0pt; - font-family:����;} + font-family:宋体;} p.5Char10, li.5Char10, div.5Char10 - {mso-style-name:"ͼ������С5�� Char1"; + {mso-style-name:"图中文字小5号 Char1"; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:9.0pt; - font-family:����;} + font-family:宋体;} p.51, li.51, div.51 - {mso-style-name:ͼ������С5��1; + {mso-style-name:图中文字小5号1; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:9.0pt; - font-family:����;} + font-family:宋体;} p.120, li.120, div.120 - {mso-style-name:��ʽ12; + {mso-style-name:样式12; margin-top:0cm; margin-right:0cm; margin-bottom:0cm; @@ -793,81 +793,81 @@ p.120, li.120, div.120 text-align:center; text-indent:-21.0pt; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.02, li.02, div.02 - {mso-style-name:����02; + {mso-style-name:封面02; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:36.0pt; - font-family:����; + font-family:宋体; font-weight:bold;} p.121, li.121, div.121 - {mso-style-name:����12; + {mso-style-name:封面12; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:18.0pt; - font-family:����; + font-family:宋体; font-weight:bold;} p.122, li.122, div.122 - {mso-style-name:�DZ���12; + {mso-style-name:非标题12; margin-top:7.8pt; margin-right:0cm; margin-bottom:7.8pt; margin-left:0cm; text-align:center; font-size:22.0pt; - font-family:����; + font-family:宋体; font-weight:bold;} p.3Char2, li.3Char2, div.3Char2 - {mso-style-name:"ͼ������3 Char2"; + {mso-style-name:"图中文字3 Char2"; margin:0cm; margin-bottom:.0001pt; text-align:center; line-height:9.0pt; font-size:8.0pt; - font-family:����;} + font-family:宋体;} p.post2, li.post2, div.post2 - {mso-style-name:�ʼ�post2; + {mso-style-name:邮件post2; margin:0cm; margin-bottom:.0001pt; text-align:right; line-height:11.0pt; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.32, li.32, div.32 - {mso-style-name:ͼ������32; + {mso-style-name:图中字体32; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.5Char2, li.5Char2, div.5Char2 - {mso-style-name:"ͼ������С5�� Char2"; + {mso-style-name:"图中文字小5号 Char2"; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:9.0pt; - font-family:����;} + font-family:宋体;} p.52, li.52, div.52 - {mso-style-name:ͼ������С5��2; + {mso-style-name:图中文字小5号2; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:9.0pt; - font-family:����;} + font-family:宋体;} p.3CharCharCharChar, li.3CharCharCharChar, div.3CharCharCharChar - {mso-style-name:"ͼ������3 Char Char Char Char"; + {mso-style-name:"图中文字3 Char Char Char Char"; margin:0cm; margin-bottom:.0001pt; text-align:center; line-height:9.0pt; font-size:8.0pt; - font-family:����;} + font-family:宋体;} p.130, li.130, div.130 - {mso-style-name:��ʽ13; + {mso-style-name:样式13; margin-top:0cm; margin-right:0cm; margin-bottom:0cm; @@ -876,129 +876,129 @@ p.130, li.130, div.130 text-align:center; text-indent:-21.0pt; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.30, li.30, div.30 - {mso-style-name:�������3; + {mso-style-name:代码程序3; margin:0cm; margin-bottom:.0001pt; font-size:10.0pt; - font-family:����;} + font-family:宋体;} p.03, li.03, div.03 - {mso-style-name:����03; + {mso-style-name:封面03; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:36.0pt; - font-family:����; + font-family:宋体; font-weight:bold;} p.131, li.131, div.131 - {mso-style-name:����13; + {mso-style-name:封面13; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:18.0pt; - font-family:����; + font-family:宋体; font-weight:bold;} p.132, li.132, div.132 - {mso-style-name:�DZ���13; + {mso-style-name:非标题13; margin-top:7.8pt; margin-right:0cm; margin-bottom:7.8pt; margin-left:0cm; text-align:center; font-size:22.0pt; - font-family:����; + font-family:宋体; font-weight:bold;} p.33, li.33, div.33 - {mso-style-name:�ı�����3; + {mso-style-name:文本居中3; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.3Char3, li.3Char3, div.3Char3 - {mso-style-name:"ͼ������3 Char3"; + {mso-style-name:"图中文字3 Char3"; margin:0cm; margin-bottom:.0001pt; text-align:center; line-height:9.0pt; font-size:8.0pt; - font-family:����;} + font-family:宋体;} p.post3, li.post3, div.post3 - {mso-style-name:�ʼ�post3; + {mso-style-name:邮件post3; margin:0cm; margin-bottom:.0001pt; text-align:right; line-height:11.0pt; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.330, li.330, div.330 - {mso-style-name:ͼ������33; + {mso-style-name:图中字体33; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.5Char20, li.5Char20, div.5Char20 - {mso-style-name:"ͼ������5�� Char2"; + {mso-style-name:"图中文字5号 Char2"; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.5CharChar2, li.5CharChar2, div.5CharChar2 - {mso-style-name:"ͼ������С5�� Char Char2"; + {mso-style-name:"图中文字小5号 Char Char2"; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:9.0pt; - font-family:����;} + font-family:宋体;} p.5Char3, li.5Char3, div.5Char3 - {mso-style-name:"ͼ������С5�� Char3"; + {mso-style-name:"图中文字小5号 Char3"; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:9.0pt; - font-family:����;} + font-family:宋体;} p.53, li.53, div.53 - {mso-style-name:ͼ������С5��3; + {mso-style-name:图中文字小5号3; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:9.0pt; - font-family:����;} + font-family:宋体;} p.3Char, li.3Char, div.3Char - {mso-style-name:"ͼ������3 Char"; - mso-style-link:"ͼ������3 Char Char5"; + {mso-style-name:"图中文字3 Char"; + mso-style-link:"图中文字3 Char Char5"; margin:0cm; margin-bottom:.0001pt; text-align:center; line-height:9.0pt; font-size:8.0pt; - font-family:����;} + font-family:宋体;} span.3CharChar5 - {mso-style-name:"ͼ������3 Char Char5"; - mso-style-link:"ͼ������3 Char"; - font-family:����;} + {mso-style-name:"图中文字3 Char Char5"; + mso-style-link:"图中文字3 Char"; + font-family:宋体;} p.54, li.54, div.54 - {mso-style-name:ͼ������С5����; + {mso-style-name:图中文字小5紧密; margin:0cm; margin-bottom:.0001pt; line-height:9.0pt; text-autospace:ideograph-numeric; font-size:9.0pt; - font-family:����;} + font-family:宋体;} p.24, li.24, div.24 - {mso-style-name:����2�Ŵ�����; + {mso-style-name:居中2号粗宋体; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:22.0pt; - font-family:����; + font-family:宋体; font-weight:bold;} p.15, li.15, div.15 - {mso-style-name:"��ʽ ���� 1 + ����"; + {mso-style-name:"样式 标题 1 + 居中"; margin-top:17.0pt; margin-right:0cm; margin-bottom:16.5pt; @@ -1006,10 +1006,10 @@ p.15, li.15, div.15 text-align:center; page-break-after:avoid; font-size:22.0pt; - font-family:����; + font-family:宋体; font-weight:bold;} p.25, li.25, div.25 - {mso-style-name:"��ʽ ���� 2 + �о�\: �����о�"; + {mso-style-name:"样式 标题 2 + 行距\: 单倍行距"; margin-top:13.0pt; margin-right:0cm; margin-bottom:13.0pt; @@ -1022,33 +1022,33 @@ p.25, li.25, div.25 font-family:"Arial","sans-serif"; font-weight:bold;} span.2Char - {mso-style-name:"���� 2 Char"; - mso-style-link:"���� 2"; + {mso-style-name:"标题 2 Char"; + mso-style-link:"标题 2"; font-family:"Arial","sans-serif"; font-weight:bold;} p.34, li.34, div.34 - {mso-style-name:�б�3; + {mso-style-name:列表3; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.35, li.35, div.35 - {mso-style-name:��3; + {mso-style-name:表3; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.4, li.4, div.4 - {mso-style-name:ͼ˵��4; + {mso-style-name:图说明4; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.40, li.40, div.40 - {mso-style-name:�б�4; + {mso-style-name:列表4; margin-top:0cm; margin-right:0cm; margin-bottom:0cm; @@ -1057,168 +1057,168 @@ p.40, li.40, div.40 text-align:center; text-indent:-21.0pt; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.41, li.41, div.41 - {mso-style-name:��4; + {mso-style-name:表4; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.55, li.55, div.55 - {mso-style-name:ͼ˵��5; + {mso-style-name:图说明5; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.56, li.56, div.56 - {mso-style-name:�б�5; + {mso-style-name:列表5; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.57, li.57, div.57 - {mso-style-name:��5; + {mso-style-name:表5; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.6, li.6, div.6 - {mso-style-name:�б�6; + {mso-style-name:列表6; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.60, li.60, div.60 - {mso-style-name:��6; + {mso-style-name:表6; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.61, li.61, div.61 - {mso-style-name:ͼ˵��6; + {mso-style-name:图说明6; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.7, li.7, div.7 - {mso-style-name:�б�7; + {mso-style-name:列表7; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.70, li.70, div.70 - {mso-style-name:ͼ˵��7; + {mso-style-name:图说明7; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.71, li.71, div.71 - {mso-style-name:��7; + {mso-style-name:表7; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.8, li.8, div.8 - {mso-style-name:�б�8; + {mso-style-name:列表8; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.9, li.9, div.9 - {mso-style-name:�б�9; + {mso-style-name:列表9; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.90, li.90, div.90 - {mso-style-name:ͼ˵��9; + {mso-style-name:图说明9; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.100, li.100, div.100 - {mso-style-name:�б�10; + {mso-style-name:列表10; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.101, li.101, div.101 - {mso-style-name:ͼ˵��10; + {mso-style-name:图说明10; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.114, li.114, div.114 - {mso-style-name:�б�11; + {mso-style-name:列表11; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.115, li.115, div.115 - {mso-style-name:ͼ˵��11; + {mso-style-name:图说明11; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.116, li.116, div.116 - {mso-style-name:��11; + {mso-style-name:表11; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.123, li.123, div.123 - {mso-style-name:�б�12; + {mso-style-name:列表12; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.124, li.124, div.124 - {mso-style-name:ͼ˵��12; + {mso-style-name:图说明12; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.133, li.133, div.133 - {mso-style-name:ͼ˵��13; - mso-style-link:"ͼ˵��13 Char"; + {mso-style-name:图说明13; + mso-style-link:"图说明13 Char"; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} span.13Char - {mso-style-name:"ͼ˵��13 Char"; - mso-style-link:ͼ˵��13; - font-family:����;} + {mso-style-name:"图说明13 Char"; + mso-style-link:图说明13; + font-family:宋体;} p.134, li.134, div.134 - {mso-style-name:�б�13; + {mso-style-name:列表13; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.26, li.26, div.26 - {mso-style-name:��¼2; + {mso-style-name:附录2; margin-top:13.0pt; margin-right:0cm; margin-bottom:13.0pt; @@ -1230,7 +1230,7 @@ p.26, li.26, div.26 font-family:"Arial","sans-serif"; font-weight:bold;} p.36, li.36, div.36 - {mso-style-name:��¼3; + {mso-style-name:附录3; margin:0cm; margin-bottom:.0001pt; text-align:justify; @@ -1240,12 +1240,12 @@ p.36, li.36, div.36 font-family:"Arial","sans-serif"; font-weight:bold;} span.3Char0 - {mso-style-name:"���� 3 Char"; - mso-style-link:"���� 3"; + {mso-style-name:"标题 3 Char"; + mso-style-link:"标题 3"; font-family:"Arial","sans-serif"; font-weight:bold;} p.16, li.16, div.16 - {mso-style-name:��¼1; + {mso-style-name:附录1; margin-top:17.0pt; margin-right:0cm; margin-bottom:16.5pt; @@ -1253,17 +1253,17 @@ p.16, li.16, div.16 text-align:center; page-break-after:avoid; font-size:22.0pt; - font-family:����; + font-family:宋体; font-weight:bold;} p.17, li.17, div.17 - {mso-style-name:��¼��1; + {mso-style-name:附录表1; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.42, li.42, div.42 - {mso-style-name:��¼4; + {mso-style-name:附录4; margin:0cm; margin-bottom:.0001pt; text-align:justify; @@ -1273,19 +1273,19 @@ p.42, li.42, div.42 font-family:"Arial","sans-serif"; font-weight:bold;} span.4Char - {mso-style-name:"���� 4 Char"; - mso-style-link:"���� 4"; + {mso-style-name:"标题 4 Char"; + mso-style-link:"标题 4"; font-family:"Arial","sans-serif"; font-weight:bold;} p.a3, li.a3, div.a3 - {mso-style-name:��¼ͼ˵��; + {mso-style-name:附录图说明; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.27, li.27, div.27 - {mso-style-name:�����2; + {mso-style-name:序标题2; margin-top:13.0pt; margin-right:0cm; margin-bottom:13.0pt; @@ -1298,7 +1298,7 @@ p.27, li.27, div.27 font-family:"Arial","sans-serif"; font-weight:bold;} p.a4, li.a4, div.a4 - {mso-style-name:�ο�����; + {mso-style-name:参考标题; margin-top:7.8pt; margin-right:0cm; margin-bottom:7.8pt; @@ -1306,10 +1306,10 @@ p.a4, li.a4, div.a4 text-align:center; page-break-after:avoid; font-size:22.0pt; - font-family:����; + font-family:宋体; font-weight:bold;} p.18, li.18, div.18 - {mso-style-name:��������1; + {mso-style-name:索引标题1; margin-top:7.8pt; margin-right:0cm; margin-bottom:7.8pt; @@ -1317,10 +1317,10 @@ p.18, li.18, div.18 text-align:center; page-break-after:avoid; font-size:22.0pt; - font-family:����; + font-family:宋体; font-weight:bold;} p.19, li.19, div.19 - {mso-style-name:�б�1; + {mso-style-name:列表1; margin-top:0cm; margin-right:0cm; margin-bottom:0cm; @@ -1329,9 +1329,9 @@ p.19, li.19, div.19 text-align:center; text-indent:-21.25pt; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.1a, li.1a, div.1a - {mso-style-name:��1; + {mso-style-name:表1; margin-top:0cm; margin-right:0cm; margin-bottom:0cm; @@ -1340,38 +1340,38 @@ p.1a, li.1a, div.1a text-align:center; text-indent:-21.25pt; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.37, li.37, div.37 - {mso-style-name:ͼ˵��3; + {mso-style-name:图说明3; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.62, li.62, div.62 - {mso-style-name:��������6��; + {mso-style-name:表中字体6号; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; layout-grid-mode:char; font-size:7.5pt; - font-family:����;} + font-family:宋体;} p.a5, li.a5, div.a5 - {mso-style-name:���Ĵ���; - mso-style-link:"���Ĵ��� Char"; + {mso-style-name:正文代码; + mso-style-link:"正文代码 Char"; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; font-size:10.5pt; - font-family:����;} + font-family:宋体;} span.Char1 - {mso-style-name:"���Ĵ��� Char"; - mso-style-link:���Ĵ���; - font-family:����;} + {mso-style-name:"正文代码 Char"; + mso-style-link:正文代码; + font-family:宋体;} p.43, li.43, div.43 - {mso-style-name:"��ʽ ���� 4 +"; + {mso-style-name:"样式 标题 4 +"; margin:0cm; margin-bottom:.0001pt; text-align:justify; @@ -1381,7 +1381,7 @@ p.43, li.43, div.43 font-family:"Arial","sans-serif"; font-weight:bold;} p.140, li.140, div.140 - {mso-style-name:��14; + {mso-style-name:表14; margin-top:0cm; margin-right:0cm; margin-bottom:0cm; @@ -1390,10 +1390,10 @@ p.140, li.140, div.140 text-align:center; text-indent:-21.25pt; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.141, li.141, div.141 - {mso-style-name:ͼ˵��14; - mso-style-link:"ͼ˵��14 Char"; + {mso-style-name:图说明14; + mso-style-link:"图说明14 Char"; margin-top:0cm; margin-right:0cm; margin-bottom:0cm; @@ -1402,62 +1402,62 @@ p.141, li.141, div.141 text-align:center; text-indent:-21.25pt; font-size:10.5pt; - font-family:����;} + font-family:宋体;} span.14Char - {mso-style-name:"ͼ˵��14 Char"; - mso-style-link:ͼ˵��14; - font-family:����;} + {mso-style-name:"图说明14 Char"; + mso-style-link:图说明14; + font-family:宋体;} p.a6, li.a6, div.a6 - {mso-style-name:�ļ�Ŀ¼��; + {mso-style-name:文件目录表; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.a7, li.a7, div.a7 - {mso-style-name:"��ʽ ���� +"; - mso-style-link:"��ʽ ���� + Char"; + {mso-style-name:"样式 正文 +"; + mso-style-link:"样式 正文 + Char"; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; font-size:10.5pt; - font-family:����;} + font-family:宋体;} span.Char2 - {mso-style-name:"��ʽ ���� + Char"; - mso-style-link:"��ʽ ���� +"; + {mso-style-name:"样式 正文 + Char"; + mso-style-link:"样式 正文 +"; font-family:"Times New Roman","serif";} p.a8, li.a8, div.a8 - {mso-style-name:������ע; + {mso-style-name:表格题注; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.a9, li.a9, div.a9 - {mso-style-name:�б���ע; + {mso-style-name:列表题注; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; font-family:"Arial","sans-serif";} p.aa, li.aa, div.aa - {mso-style-name:ͼ��ע; + {mso-style-name:图题注; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; font-family:"Arial","sans-serif";} p.ab, li.ab, div.ab - {mso-style-name:������ע; + {mso-style-name:程序题注; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; font-family:"Arial","sans-serif";} p.ac, li.ac, div.ac - {mso-style-name:��������; + {mso-style-name:框中文字; margin-top:0cm; margin-right:21.0pt; margin-bottom:0cm; @@ -1468,9 +1468,9 @@ p.ac, li.ac, div.ac border:none; padding:0cm; font-size:9.0pt; - font-family:����;} + font-family:宋体;} p.125, li.125, div.125 - {mso-style-name:"��ʽ ���� 1 + ����2"; + {mso-style-name:"样式 标题 1 + 居中2"; margin-top:17.0pt; margin-right:0cm; margin-bottom:16.5pt; @@ -1478,17 +1478,17 @@ p.125, li.125, div.125 text-align:center; page-break-after:avoid; font-size:22.0pt; - font-family:����; + font-family:宋体; font-weight:bold;} p.ad, li.ad, div.ad - {mso-style-name:"��ʽ ��ע + ���� ��� ����"; + {mso-style-name:"样式 题注 + 宋体 五号 居中"; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:黑体;} p.1b, li.1b, div.1b - {mso-style-name:�����1; + {mso-style-name:序标题1; margin-top:17.0pt; margin-right:0cm; margin-bottom:16.5pt; @@ -1496,65 +1496,65 @@ p.1b, li.1b, div.1b line-height:240%; page-break-after:avoid; font-size:16.0pt; - font-family:����; + font-family:宋体; font-weight:bold;} p.38, li.38, div.38 - {mso-style-name:�����3; + {mso-style-name:序标题3; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; page-break-after:avoid; font-size:12.0pt; - font-family:����С���μ���;} + font-family:方正小标宋简体;} p.63, li.63, div.63 - {mso-style-name:��������6��; + {mso-style-name:表中文字6号; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; font-size:7.5pt; - font-family:����;} + font-family:宋体;} p.64, li.64, div.64 - {mso-style-name:ͼ������6�������; + {mso-style-name:图中文字6号左对齐; margin:0cm; margin-bottom:.0001pt; line-height:10.0pt; layout-grid-mode:char; font-size:7.5pt; - font-family:����;} + font-family:宋体;} p.65, li.65, div.65 - {mso-style-name:ͼ������6��; - mso-style-link:"ͼ������6�� Char"; + {mso-style-name:图中文字6号; + mso-style-link:"图中文字6号 Char"; margin:0cm; margin-bottom:.0001pt; text-align:center; line-height:10.0pt; layout-grid-mode:char; font-size:7.5pt; - font-family:����;} + font-family:宋体;} span.6Char - {mso-style-name:"ͼ������6�� Char"; - mso-style-link:ͼ������6��; - font-family:����;} + {mso-style-name:"图中文字6号 Char"; + mso-style-link:图中文字6号; + font-family:宋体;} p.ae, li.ae, div.ae - {mso-style-name:ͼ��; + {mso-style-name:图标; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.28, li.28, div.28 - {mso-style-name:ͼ��2; + {mso-style-name:图标2; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.af, li.af, div.af - {mso-style-name:ϰ�����; + {mso-style-name:习题标题; margin-top:6.0pt; margin-right:0cm; margin-bottom:0cm; @@ -1564,29 +1564,29 @@ p.af, li.af, div.af text-justify:inter-ideograph; page-break-after:avoid; font-size:14.0pt; - font-family:����;} + font-family:黑体;} p.1c, li.1c, div.1c - {mso-style-name:���ֱ��1; + {mso-style-name:部分编号1; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; font-size:16.0pt; - font-family:����;} + font-family:宋体;} p.af0, li.af0, div.af0 - {mso-style-name:������; + {mso-style-name:表标题; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; font-family:"Arial","sans-serif";} p.af1, li.af1, div.af1 - {mso-style-name:"��ʽ ��ע + ����"; + {mso-style-name:"样式 题注 + 居中"; margin:0cm; margin-bottom:.0001pt; text-align:center; font-size:10.5pt; - font-family:����;} + font-family:宋体;} p.ListTitle, li.ListTitle, div.ListTitle {mso-style-name:ListTitle; margin:0cm; @@ -1628,186 +1628,186 @@ p.RightText, li.RightText, div.RightText border:none; padding:0cm; font-size:9.0pt; - font-family:����;} + font-family:宋体;} p.af2, li.af2, div.af2 - {mso-style-name:��������С��; + {mso-style-name:表中文字小五; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; font-size:9.0pt; - font-family:����;} + font-family:宋体;} p.af3, li.af3, div.af3 - {mso-style-name:�ؼ���; - mso-style-link:"�ؼ��� Char"; + {mso-style-name:关键词; + mso-style-link:"关键词 Char"; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; font-size:10.5pt; - font-family:����;} + font-family:宋体;} span.Char3 - {mso-style-name:"�ؼ��� Char"; - mso-style-link:�ؼ���; - font-family:����;} + {mso-style-name:"关键词 Char"; + mso-style-link:关键词; + font-family:宋体;} p.af4, li.af4, div.af4 - {mso-style-name:�ļ���; - mso-style-link:"�ļ��� Char"; + {mso-style-name:文件名; + mso-style-link:"文件名 Char"; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; font-size:10.5pt; - font-family:����;} + font-family:宋体;} span.Char4 - {mso-style-name:"�ļ��� Char"; - mso-style-link:�ļ���; - font-family:����;} + {mso-style-name:"文件名 Char"; + mso-style-link:文件名; + font-family:宋体;} p.af5, li.af5, div.af5 - {mso-style-name:ѡ��; - mso-style-link:"ѡ�� Char"; + {mso-style-name:选项; + mso-style-link:"选项 Char"; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; font-size:10.5pt; - font-family:����;} + font-family:宋体;} span.Char5 - {mso-style-name:"ѡ�� Char"; - mso-style-link:ѡ��; - font-family:����;} + {mso-style-name:"选项 Char"; + mso-style-link:选项; + font-family:宋体;} p.af6, li.af6, div.af6 - {mso-style-name:������; - mso-style-link:"������ Char"; + {mso-style-name:命令行; + mso-style-link:"命令行 Char"; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; font-size:10.5pt; - font-family:����;} + font-family:宋体;} span.Char6 - {mso-style-name:"������ Char"; - mso-style-link:������; - font-family:����;} + {mso-style-name:"命令行 Char"; + mso-style-link:命令行; + font-family:宋体;} p.af7, li.af7, div.af7 - {mso-style-name:������; - mso-style-link:"������ Char"; + {mso-style-name:函数名; + mso-style-link:"函数名 Char"; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; font-size:10.5pt; - font-family:����;} + font-family:宋体;} span.Char7 - {mso-style-name:"������ Char"; - mso-style-link:������; - font-family:����;} + {mso-style-name:"函数名 Char"; + mso-style-link:函数名; + font-family:宋体;} p.af8, li.af8, div.af8 - {mso-style-name:�Ĵ�����; - mso-style-link:"�Ĵ����� Char"; + {mso-style-name:寄存器名; + mso-style-link:"寄存器名 Char"; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; font-size:10.5pt; - font-family:����;} + font-family:宋体;} span.Char8 - {mso-style-name:"�Ĵ����� Char"; - mso-style-link:�Ĵ�����; + {mso-style-name:"寄存器名 Char"; + mso-style-link:寄存器名; font-family:"Times New Roman","serif";} p.af9, li.af9, div.af9 - {mso-style-name:������; - mso-style-link:"������ Char"; + {mso-style-name:变量名; + mso-style-link:"变量名 Char"; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; font-size:10.5pt; - font-family:����;} + font-family:宋体;} span.Char9 - {mso-style-name:"������ Char"; - mso-style-link:������; - font-family:����;} + {mso-style-name:"变量名 Char"; + mso-style-link:变量名; + font-family:宋体;} p.58, li.58, div.58 - {mso-style-name:ͼ������С5����; + {mso-style-name:图中文字小5号左; margin:0cm; margin-bottom:.0001pt; font-size:9.0pt; - font-family:����;} + font-family:宋体;} p.59, li.59, div.59 - {mso-style-name:ͼ������С5�ſ���; + {mso-style-name:图中文字小5号靠左; margin:0cm; margin-bottom:.0001pt; layout-grid-mode:char; font-size:9.0pt; - font-family:����;} + font-family:宋体;} p.926, li.926, div.926 - {mso-style-name:"��ʽ ������� + ���\: 9\.26 ����"; + {mso-style-name:"样式 代码程序 + 左侧\: 9\.26 厘米"; margin:0cm; margin-bottom:.0001pt; layout-grid-mode:char; font-size:10.0pt; - font-family:����;} + font-family:宋体;} span.5Char4 - {mso-style-name:"���� 5 Char"; - mso-style-link:"���� 5"; + {mso-style-name:"标题 5 Char"; + mso-style-link:"标题 5"; font-weight:bold;} span.6Char0 - {mso-style-name:"���� 6 Char"; - mso-style-link:"���� 6"; + {mso-style-name:"标题 6 Char"; + mso-style-link:"标题 6"; font-family:"Arial","sans-serif"; font-weight:bold;} span.7Char - {mso-style-name:"���� 7 Char"; - mso-style-link:"���� 7"; + {mso-style-name:"标题 7 Char"; + mso-style-link:"标题 7"; font-weight:bold;} span.8Char - {mso-style-name:"���� 8 Char"; - mso-style-link:"���� 8"; + {mso-style-name:"标题 8 Char"; + mso-style-link:"标题 8"; font-family:"Arial","sans-serif";} span.9Char - {mso-style-name:"���� 9 Char"; - mso-style-link:"���� 9"; + {mso-style-name:"标题 9 Char"; + mso-style-link:"标题 9"; font-family:"Arial","sans-serif";} span.Chara - {mso-style-name:"��ע�ı� Char"; - mso-style-link:��ע�ı�; - font-family:����;} + {mso-style-name:"脚注文本 Char"; + mso-style-link:脚注文本; + font-family:宋体;} span.Charb - {mso-style-name:"��ע���� Char"; - mso-style-link:��ע����; - font-family:����;} + {mso-style-name:"批注文字 Char"; + mso-style-link:批注文字; + font-family:宋体;} span.Charc - {mso-style-name:"ҳü Char"; - mso-style-link:ҳü; - font-family:����;} + {mso-style-name:"页眉 Char"; + mso-style-link:页眉; + font-family:宋体;} span.Chard - {mso-style-name:"ҳ�� Char"; - mso-style-link:ҳ��; - font-family:����;} + {mso-style-name:"页脚 Char"; + mso-style-link:页脚; + font-family:宋体;} span.Chare - {mso-style-name:"���� Char"; - mso-style-link:����; - font-family:����;} + {mso-style-name:"日期 Char"; + mso-style-link:日期; + font-family:宋体;} span.HTMLChar - {mso-style-name:"HTML Ԥ���ʽ Char\,HTML Ԥ�ȸ�ʽ�� Char\,HTML Ԥ�ȸ�ʽ��1 Char\,HTML Ԥ�ȸ�ʽ��2 Char\,HTML Ԥ�ȸ�ʽ��3 Char"; - mso-style-link:"HTML Ԥ���ʽ\,HTML Ԥ�ȸ�ʽ��\,HTML Ԥ�ȸ�ʽ��1\,HTML Ԥ�ȸ�ʽ��2\,HTML Ԥ�ȸ�ʽ��3"; - font-family:����;} + {mso-style-name:"HTML 预设格式 Char\,HTML 预先格式化 Char\,HTML 预先格式化1 Char\,HTML 预先格式化2 Char\,HTML 预先格式化3 Char"; + mso-style-link:"HTML 预设格式\,HTML 预先格式化\,HTML 预先格式化1\,HTML 预先格式化2\,HTML 预先格式化3"; + font-family:宋体;} span.Charf - {mso-style-name:"��ע���� Char"; - mso-style-link:��ע����; - font-family:����; + {mso-style-name:"批注主题 Char"; + mso-style-link:批注主题; + font-family:宋体; font-weight:bold;} span.Charf0 - {mso-style-name:"��ע���ı� Char"; - mso-style-link:��ע���ı�; - font-family:����;} + {mso-style-name:"批注框文本 Char"; + mso-style-link:批注框文本; + font-family:宋体;} span.3CharChar1 - {mso-style-name:"ͼ������3 Char Char1"; - font-family:����;} + {mso-style-name:"图中文字3 Char Char1"; + font-family:宋体;} span.3CharChar3 - {mso-style-name:"ͼ������3 Char Char3"; - font-family:����;} + {mso-style-name:"图中文字3 Char Char3"; + font-family:宋体;} .MsoChpDefault {font-size:10.0pt;} /* Page Definitions */ @@ -1831,7 +1831,7 @@ ul
/*
-* 'buffer.c'����ʵ�ֻ��������ٻ��湦�ܡ�ͨ�������жϴ������̸ı仺�����������õ�
+* 'buffer.c'用于实现缓冲区高速缓存功能。通过不让中断处理过程改变缓冲区,而是让调
-* ������ִ�У������˾�����������Ȼ���ı��������⣩��ע�⣡�����жϿ��Ի���һ����
+* 用者来执行,避免了竞争条件(当然除改变数据以外)。注意!由于中断可以唤醒一个调
-* ���ߣ���˾���Ҫ�����ж�ָ�cli-sti��������������ڵ��ö�˯�ߡ�����Ҫ�dz��ؿ�
+* 用者,因此就需要开关中断指令(cli-sti)序列来检测由于调用而睡眠。但需要非常地快
-* ����ϣ������������
+* (我希望是这样)。
*/
@@ -1903,67 +1903,67 @@ invalidate changed floppy-disk-caches./*
-* ע�⣡��һ������Ӧ�����������������Ƿ�����������������Ƿ���
+* 注意!有一个程序应不属于这里:检测软盘是否更换。但我想这里是放置
-* �ó�����õĵط��ˣ���Ϊ����Ҫʹ�Ѹ������̻���ʧЧ��
+* 该程序最好的地方了,因为它需要使已更换软盘缓冲失效。
*/
20
21 -#include <stdarg.h> // ������ͷ�ļ����Ժ����ʽ������������б�����Ҫ˵����-��
+#include <stdarg.h> // 标准参数头文件。以宏的形式定义变量参数列表。主要说明了-个-// ����(va_list)��������(va_start, -va_arg��va_end)������
+// 类型(va_list)和三个宏(va_start, +va_arg和va_end),用于-// vsprintf��vprintf��vfprintf������
+// vsprintf、vprintf、vfprintf函数。22
23 -#include <linux/config.h> // �ں�����ͷ�ļ�������������Ժ�Ӳ�����ͣ�HD_TYPE����ѡ�
+#include <linux/config.h> // 内核配置头文件。定义键盘语言和硬盘类型(HD_TYPE)可选项。24 -#include <linux/sched.h> // ���ȳ���ͷ�ļ�������������ṹtask_struct������0�����ݣ�
+#include <linux/sched.h> // 调度程序头文件,定义了任务结构task_struct、任务0的数据,-// ����һЩ�й��������������úͻ�ȡ��Ƕ��ʽ��ຯ������䡣
+// 还有一些有关描述符参数设置和获取的嵌入式汇编函数宏语句。25 -#include <linux/kernel.h> // �ں�ͷ�ļ�������һЩ�ں˳��ú�����ԭ�ζ��塣
+#include <linux/kernel.h> // 内核头文件。含有一些内核常用函数的原形定义。26 #include -<asm/system.h> // ϵͳͷ�ļ������������û���������/�ж��ŵȵ�Ƕ����ꡣ
+<asm/system.h> // 系统头文件。定义了设置或修改描述符/中断门等的嵌入汇编宏。27 -#include <asm/io.h> // ioͷ�ļ�������Ӳ���˿�����/���������䡣
+#include <asm/io.h> // io头文件。定义硬件端口输入/输出宏汇编语句。28
-// ����end���ɱ���ʱ�����ӳ���ld���ɣ����ڱ����ں˴����ĩ�ˣ���ָ���ں�ģ��ĩ��
+// 变量end是由编译时的连接程序ld生成,用于表明内核代码的末端,即指明内核模块末端
-// λ�ã��μ�����!δ�ҵ�����Դ����Ҳ���Դӱ����ں�ʱ���ɵ� System.map�ļ��в����������������
+// 位置,参见错误!未找到引用源。。也可以从编译内核时生成的 System.map文件中查出。这里用它来表
-// �����ٻ�������ʼ���ں˴���ĩ��λ�á�
+// 明高速缓冲区开始于内核代码末端位置。
-// ��33���ϵ�buffer_wait�����ǵȴ����л�����˯�ߵ��������ͷָ�롣���뻺���ͷ
+// 第33行上的buffer_wait变量是等待空闲缓冲块而睡眠的任务队列头指针。它与缓冲块头
-// ���ṹ��b_waitָ������ò�ͬ������������һ����������������ϵͳȱ�����ÿ��л�
+// 部结构中b_wait指针的作用不同。当任务申请一个缓冲块而正好遇到系统缺乏可用空闲缓
-// ���ʱ����ǰ����ͻᱻ���ӵ�buffer_wait˯�ߵȴ������С���b_wait����ר�Ź��ȴ�
+// 冲块时,当前任务就会被添加到buffer_wait睡眠等待队列中。而b_wait则是专门供等待
-// ָ������飨��b_wait��Ӧ�Ļ���飩������ʹ�õĵȴ�����ͷָ�롣
+// 指定缓冲块(即b_wait对应的缓冲块)的任务使用的等待队列头指针。
29 extern int end;
@@ -1976,60 +1976,60 @@ blue'>buffer_head *) &end;31 struct buffer_head * hash_table[NR_HASH]; - // NR_HASH = 307�
+ // NR_HASH = 307项。32 static struct buffer_head * free_list; -// ���л��������ͷָ�롣
+// 空闲缓冲块链表头指针。33 static struct task_struct * buffer_wait = NULL; -// �ȴ����л�����˯�ߵ�������С�
+// 等待空闲缓冲块而睡眠的任务队列。-
// ���涨��ϵͳ�������к��еĻ������������NR_BUFFERS��һ��������linux/fs.hͷ
+// 下面定义系统缓冲区中含有的缓冲块个数。这里,NR_BUFFERS是一个定义在linux/fs.h头
-// �ļ���48�еĺ꣬��ֵ���DZ�����nr_buffers��������fs.h�ļ���172������Ϊȫ�ֱ�����
+// 文件第48行的宏,其值即是变量名nr_buffers,并且在fs.h文件第172行声明为全局变量。
-// ��д����ͨ������һ�������ƣ�Linus������д������Ϊ�����������д�����������ر�ʾ
+// 大写名称通常都是一个宏名称,Linus这样编写代码是为了利用这个大写名称来隐含地表示
-// nr_buffers��һ�����ں˳�ʼ��֮���ٸı�ġ��������������ڳ�ʼ������ // nr_buffers是一个在内核初始化之后不再改变的“常量”。它将在初始化函数buffer_init()
-// �б����ã���371�У���
+// 中被设置(第371行)。
34 int NR_BUFFERS = 0; // -ϵͳ���л���������
+系统含有缓冲块个数。35
-//// �ȴ�ָ������������
+//// 等待指定缓冲块解锁。
-// ���ָ���Ļ����bh�Ѿ��������ý��̲����жϵ�˯���ڸû����ĵȴ�����b_wait�С�
+// 如果指定的缓冲块bh已经上锁就让进程不可中断地睡眠在该缓冲块的等待队列b_wait中。
-// �ڻ�������ʱ����ȴ������ϵ����н��̽������ѡ���Ȼ���ڹر��жϣ�cli��֮��ȥ˯
+// 在缓冲块解锁时,其等待队列上的所有进程将被唤醒。虽然是在关闭中断(cli)之后去睡
-// �ߵģ���������������Ӱ����������������������Ӧ�жϡ���Ϊÿ�����̶����Լ���TSS��
+// 眠的,但这样做并不会影响在其他进程上下文中响应中断。因为每个进程都在自己的TSS段
-// �б����˱�־�Ĵ���EFLAGS��ֵ�������ڽ����л�ʱCPU�е�ǰEFLAGS��ֵҲ��֮�ı䡣
+// 中保存了标志寄存器EFLAGS的值,所以在进程切换时CPU中当前EFLAGS的值也随之改变。
-// ʹ��sleep_on()����˯��״̬�Ľ�����Ҫ��wake_up()��ȷ�ػ��ѡ�
+// 使用sleep_on()进入睡眠状态的进程需要用wake_up()明确地唤醒。
36
static inline void wait_on_buffer(struct
@@ -2039,28 +2039,28 @@ static inline void wait_on_buffer(struct
38
cli();
-// ���жϡ�
39 while (bh->b_lock) -// ����ѱ���������̽���˯�ߣ��ȴ��������
+// 如果已被上锁则进程进入睡眠,等待其解锁。40 sleep_on(&bh->b_wait);
41 sti(); -// ���жϡ�
+// 开中断。42 }
43
-//// �豸����ͬ����
+//// 设备数据同步。
-// ͬ���豸���ڴ���ٻ��������ݡ����У�sync_inodes()������inode.c��59�С�
+// 同步设备和内存高速缓冲中数据。其中,sync_inodes()定义在inode.c,59行。
44 int sys_sync(void)
@@ -2075,12 +2075,12 @@ struct buffer_head * bh;48
-// ���ȵ���i�ڵ�ͬ�����������ڴ�i�ڵ���������Ĺ���i�ڵ�д����ٻ����С�Ȼ��
+// 首先调用i节点同步函数,把内存i节点表中所有修改过的i节点写入高速缓冲中。然后
-// ɨ�����и��ٻ����������ѱ��ĵĻ�������д����������������д�����У�����
+// 扫描所有高速缓冲区,对已被修改的缓冲块产生写盘请求,将缓冲中数据写入盘中,做到
-// ���ٻ����е��������豸�е�ͬ����
+// 高速缓冲中的数据与设备中的同步。
49 sync_inodes(); /* @@ -2088,21 +2088,21 @@ write out inodes into buffers */
50 bh = start_buffer; -// bhָ������ʼ����
+// bh指向缓冲区开始处。51 for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
52 wait_on_buffer(bh); -// �ȴ�����������������������Ļ�����
+// 等待缓冲区解锁(如果已上锁的话)。53 if (bh->b_dirt)
54 ll_rw_block(WRITE,bh); -// ����д�豸������
+// 产生写设备块请求。55 }
@@ -2114,15 +2114,15 @@ return 0;58
-//// ��ָ���豸���и��ٻ����������豸�����ݵ�ͬ��������
+//// 对指定设备进行高速缓冲数据与设备上数据的同步操作。
-// �ú��������������ٻ����������л���顣����ָ���豸dev�Ļ���飬���������ѱ���
+// 该函数首先搜索高速缓冲区中所有缓冲块。对于指定设备dev的缓冲块,若其数据已被修改
-// ����д�����У�ͬ����������Ȼ����ڴ���i�ڵ������д����ٻ����С�֮���ٶ�ָ����
+// 过就写入盘中(同步操作)。然后把内存中i节点表数据写入高速缓冲中。之后再对指定设
-// ��devִ��һ����������ͬ��д�̲�����
+// 备dev执行一次与上述相同的写盘操作。
59 int sync_dev(int dev)
@@ -2137,22 +2137,22 @@ struct buffer_head * bh;63
-// ���ȶԲ���ָ�����豸ִ������ͬ�����������豸�ϵ���������ٻ������е�����ͬ����
+// 首先对参数指定的设备执行数据同步操作,让设备上的数据与高速缓冲区中的数据同步。
-// ������ɨ����ٻ����������л���飬��ָ���豸dev�Ļ���飬�ȼ�����Ƿ��ѱ�������
+// 方法是扫描高速缓冲区中所有缓冲块,对指定设备dev的缓冲块,先检测其是否已被上锁,
-// ���ѱ�������˯�ߵȴ��������Ȼ�����ж�һ�θû�����Ƿ���ָ���豸�Ļ���鲢��
+// 若已被上锁就睡眠等待其解锁。然后再判断一次该缓冲块是否还是指定设备的缓冲块并且
-// ���Ĺ���b_dirt��־��λ�������ǾͶ���ִ��д�̲�������Ϊ������˯���ڼ�û����
+// 已修改过(b_dirt标志置位),若是就对其执行写盘操作。因为在我们睡眠期间该缓冲块
-// �п����ѱ��ͷŻ��߱�Ų�����ã������ڼ���ִ��ǰ��Ҫ�ٴ��ж�һ�¸û�����Ƿ���
+// 有可能已被释放或者被挪作它用,所以在继续执行前需要再次判断一下该缓冲块是否还是
-// ָ���豸�Ļ���飬
+// 指定设备的缓冲块,
64 bh = start_buffer; - // bhָ������ʼ����
+ // bh指向缓冲区开始处。 65
for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
@@ -2160,14 +2160,14 @@ for (i=0 ; i<NR_BUFFERS ; i++,bh++) {&
66
if (bh->b_dev != dev)
-// �����豸dev�Ļ�����������
67 continue;
68 wait_on_buffer(bh); -// �ȴ�����������������������Ļ�����
+// 等待缓冲区解锁(如果已上锁的话)。69 if (bh->b_dev == dev && bh->b_dirt)
@@ -2178,21 +2178,21 @@ if (bh->b_dev == dev && bh->b_dirt)71 }
-// �ٽ�i�ڵ�����д����ٻ��塣��i�ڵ��inode_table�е�inode�뻺���е���Ϣͬ����
+// 再将i节点数据写入高速缓冲。让i节点表inode_table中的inode与缓冲中的信息同步。
72 sync_inodes();
-// Ȼ���ڸ��ٻ����е����ݸ���֮���ٰ��������豸�е�����ͬ���������������ͬ������
+// 然后在高速缓冲中的数据更新之后,再把它们与设备中的数据同步。这里采用两遍同步操作
-// ��Ϊ������ں�ִ��Ч�ʡ���һ�黺����ͬ�������������ں������ࡰ��顱��ɾ���ʹ��
+// 是为了提高内核执行效率。第一遍缓冲区同步操作可以让内核中许多“脏块”变干净,使得
-// i�ڵ��ͬ�������ܹ���Чִ�С����λ�����ͬ�����������Щ����i�ڵ�ͬ���������ֱ�
+// i节点的同步操作能够高效执行。本次缓冲区同步操作则把那些由于i节点同步操作而又变
-// ��Ļ�������豸������ͬ����
+// 脏的缓冲块与设备中数据同步。
73 bh = start_buffer;
@@ -2225,10 +2225,10 @@ return 0;83
-//// ʹָ���豸�ڸ��ٻ������е�������Ч��
+//// 使指定设备在高速缓冲区中的数据无效。
-// ɨ����ٻ����������л���顣��ָ���豸�Ļ���鸴λ����Ч(����)��־�����ı�־��
+// 扫描高速缓冲区中所有缓冲块。对指定设备的缓冲块复位其有效(更新)标志和已修改标志。
84 void inline invalidate_buffers(int dev)
@@ -2252,17 +2252,17 @@ for (i=0 ; i<NR_BUFFERS ; i++,bh++) {<91 if (bh->b_dev != dev) // -�������ָ���豸�Ļ���飬��
+如果不是指定设备的缓冲块,则92 continue; -// ����ɨ����һ�顣
+// 继续扫描下一块。93 wait_on_buffer(bh); -// �ȴ��û���������������ѱ���������
+// 等待该缓冲区解锁(如果已被上锁)。 -// ���ڽ���ִ�й�˯�ߵȴ���������Ҫ���ж�һ�»������Ƿ���ָ���豸�ġ�
+// 由于进程执行过睡眠等待,所以需要再判断一下缓冲区是否是指定设备的。
94 if (bh->b_dev == dev)
@@ -2329,26 +2329,26 @@ lang=EN-US> *//*
-* ���ӳ�����һ�������Ƿ��ѱ�����������Ѿ�������ʹ���ٻ������������
+* 该子程序检查一个软盘是否已被更换,如果已经更换就使高速缓冲中与该软驱
-* ��Ӧ�����л�������Ч�����ӳ��������˵��������������Ҫ������ʹ������
+* 对应的所有缓冲区无效。该子程序相对来说较慢,所以我们要尽量少使用它。
-* ���Խ���ִ��'mount'��'open'ʱ�ŵ��������������ǽ��ٶȺ�ʵ�������ϵ�
+* 所以仅在执行'mount'或'open'时才调用它。我想这是将速度和实用性相结合的
-* ��÷��������ڲ��������и������̣��ͻᵼ�����ݵĶ�ʧ�����Ǿ�����ȡJ��
+* 最好方法。若在操作过程中更换软盘,就会导致数据的丢失。这是咎由自取J。
*
-* ע�⣡����Ŀǰ���ӳ�����������̣��Ժ��κο��ƶ����ʵĿ��豸����ʹ�ø�
+* 注意!尽管目前该子程序仅用于软盘,以后任何可移动介质的块设备都将使用该
-* ����mount/open��������Ҫ֪�������̻�������ʲô������ʡ�
+* 程序,mount/open操作不需要知道是软盘还是其他什么特殊介质。
*/
-//// �������Ƿ����������Ѹ�����ʹ��Ӧ���ٻ�������Ч��
+//// 检查磁盘是否更换,如果已更换就使对应高速缓冲区无效。
113 void check_disk_change(int @@ -2363,11 +2363,11 @@ lang=EN-US> int i;
116
-// ���ȼ��һ���Dz��������豸����Ϊ���ڽ�֧�����̿��ƶ����ʡ�����������˳���Ȼ��
+// 首先检测一下是不是软盘设备。因为现在仅支持软盘可移动介质。如果不是则退出。然后
-// ���������Ƿ��Ѹ��������û�����˳���floppy_change()��blk_drv/floppy.c��139�С�
+// 测试软盘是否已更换,如果没有则退出。floppy_change()在blk_drv/floppy.c第139行。
117 if (floppy_change(dev & 0x03))
lang=EN-US> return; -// �����Ѿ������������ͷŶ�Ӧ�豸��i�ڵ�λͼ������λͼ��ռ�ĸ��ٻ���������ʹ��
+// 软盘已经更换,所以释放对应设备的i节点位图和逻辑块位图所占的高速缓冲区;并使该
-// �豸��i�ڵ�����ݿ���Ϣ��ռ��ĸ��ٻ������Ч��
+// 设备的i节点和数据块信息所占踞的高速缓冲块无效。
121 for (i=0 ; i< }
127
-// �������д�����hash��ɢ�У����������hash����ļ���ꡣ
+// 下面两行代码是hash(散列)函数定义和hash表项的计算宏。
-// hash������Ҫ�����Ǽ��ٲ��ұȽ�Ԫ�������ѵ�ʱ�䡣ͨ����Ԫ�صĴ洢λ����ؼ���֮��
+// hash表的主要作用是减少查找比较元素所花费的时间。通过在元素的存储位置与关键字之间
-// ����һ����Ӧ��ϵ��hash�����������ǾͿ���ֱ��ͨ�������������̲�ѯ��ָ����Ԫ�ء���
+// 建立一个对应关系(hash函数),我们就可以直接通过函数计算立刻查询到指定的元素。建
-// ��hash������ָ��������Ҫ�Ǿ���ȷ��ɢ�е��κ�������ĸ��ʻ�����ȡ����������ķ���
+// 立hash函数的指导条件主要是尽量确保散列到任何数组项的概率基本相等。建立函数的方法
-// �ж��֣�����Linux 0.12��Ҫ�����˹ؼ��ֳ�������������Ϊ����Ѱ�ҵĻ����������������
+// 有多种,这里Linux 0.12主要采用了关键字除留余数法。因为我们寻找的缓冲块有两个条件,
-// ���豸��dev�ͻ�����block�������Ƶ�hash�����϶���Ҫ�����������ؼ�ֵ����������
+// 即设备号dev和缓冲块号block,因此设计的hash函数肯定需要包含这两个关键值。这里两个
-// �ؼ��ֵ�������ֻ�Ǽ���ؼ�ֵ��һ�ַ������ٶԹؼ�ֵ����MOD����Ϳ��Ա�֤��������
+// 关键字的异或操作只是计算关键值的一种方法。再对关键值进行MOD运算就可以保证函数所计
-// ��õ���ֵ�����ں��������Χ�ڡ�
+// 算得到的值都处于函数数组项范围内。
128 #define _hashfn(dev,block) @@ -2448,9 +2448,9 @@ style='color:blue'>hash_table[_hashfn130
-//// ��hash���кͿ��л��������������顣
+//// 从hash队列和空闲缓冲队列中移走缓冲块。
-// hash������˫�������ṹ�����л���������˫��ѭ�������ṹ��
+// hash队列是双向链表结构,空闲缓冲块队列是双向循环链表结构。
131 static inline void remove_from_queues(struct @@ -2462,7 +2462,7 @@ lang=EN-US> {
133 /* remove from hash-queue */
-/* ��hash�������Ƴ������ /* 从hash队列中移除缓冲块 */
134 if (bh->b_prev) lang=EN-US> bh->b_prev->b_next = bh->b_next;
-// ����û������Ǹö��е�ͷһ���飬����hash���Ķ�Ӧ��ָ�����е���һ����������
+// 如果该缓冲区是该队列的头一个块,则让hash表的对应项指向本队列中的下一个缓冲区。
138 if (
140 /* remove from free list */
-/* �ӿ��л��������Ƴ������ /* 从空闲缓冲块表中移除缓冲块 */
141
lang=EN-US> bh->b_next_free->b_prev_free = bh->b_prev_free; -// �����������ͷָ��������������ָ����һ��������
+// 如果空闲链表头指向本缓冲区,则让其指向下一缓冲区。
145 if ( }
148
-//// �����������������β����ͬʱ����hash�����С�
+//// 将缓冲块插入空闲链表尾部,同时放入hash队列中。
149 static inline void insert_into_queues(struct @@ -2543,7 +2543,7 @@ lang=EN-US> {
151 /* put at end of free list */
-/* ���ڿ�������ĩβ�� /* 放在空闲链表末尾处 */
152free_list->b_prev_free = bh;
156 /* put the buffer in new hash-queue if it has a device */
-/* ����û�����Ӧһ���豸�����������hash������ */
+/* 如果该缓冲块对应一个设备,则将其插入新hash队列中 */
-// ��ע�hash��ij���1�β�����ʱ��hash()����ֵ�϶�ΪNULL����˴�ʱ��161����
+// 请注意当hash表某项第1次插入项时,hash()计算值肯定为NULL,因此此时第161行上
-// �õ���bh->b_next�϶���NULL�����Ե�163����Ӧ����bh->b_next��ΪNULLʱ���ܸ�
+// 得到的bh->b_next肯定是NULL,所以第163行上应该在bh->b_next不为NULL时才能给
-// b_prev��bhֵ������163��ǰӦ�������жϡ�if -(bh->b_next)�����ô���0.96���
+// b_prev赋bh值。即第163行前应该增加判断“if +(bh->b_next)”。该错误到0.96版后
-// �ű�������
+// 才被纠正。
157 bh->b_prev = hash(bh->b_dev,bh->b_blocknr) = bh;
163 bh->b_next->b_prev = bh; // -�˾�ǰӦ���ӡ�if (bh->b_next)���жϡ�
+此句前应添加“if (bh->b_next)”判断。164 }
@@ -2616,10 +2616,10 @@ lang=EN-US> }165
-//// ����hash���ڸ��ٻ�����Ѱ�Ҹ����豸��ָ����ŵĻ������顣
+//// 利用hash表在高速缓冲中寻找给定设备和指定块号的缓冲区块。
-// ����ҵ��ػ��������ָ�룬����NULL��
+// 如果找到则返回缓冲区块的指针,否则返回NULL。
166 static struct buffer_head * buffer_head * tmp;
169
-// ����hash����Ѱ��ָ���豸�źͿ�ŵĻ���顣
+// 搜索hash表,寻找指定设备号和块号的缓冲块。
170 for (tmp = */
/*
-* ����Ϊʲô���������ӵģ�����������... ԭ���Ǿ�����������������û�ж�
+* 代码为什么会是这样子的?我听见你问... 原因是竞争条件。由于我们没有对
-* ����������������������ڶ�ȡ�����е����ݣ�����ô�����ǣ����̣�˯��ʱ
+* 缓冲块上锁(除非我们正在读取它们中的数据),那么当我们(进程)睡眠时
-* �������ܻᷢ��һЩ���⣨����һ���������¸û�����������Ŀǰ
+* 缓冲块可能会发生一些问题(例如一个读错误将导致该缓冲块出错)。目前
-* �������ʵ�����Dz��ᷢ���ģ��������Ĵ����Ѿ������ˡ�
+* 这种情况实际上是不会发生的,但处理的代码已经准备好了。
*/
-//// ����hash���ڸ��ٻ�������Ѱ��ָ���Ļ���顣���ҵ���Ըû�������������ؿ�ͷָ�롣
+//// 利用hash表在高速缓冲区中寻找指定的缓冲块。若找到则对该缓冲块上锁并返回块头指针。
183 struct buffer_head *
187 for (;;) {
-// �ڸ��ٻ�����Ѱ�Ҹ����豸��ָ����Ļ������飬���û���ҵ���NULL���˳���
+// 在高速缓冲中寻找给定设备和指定块的缓冲区块,如果没有找到则返回NULL,退出。
188 @@ -2730,9 +2730,9 @@ if (!(bh=find_buffer(dev,block)))< lang=EN-US> return NULL;
-// �Ըû�����������ü��������ȴ��û�������������ѱ������������ھ�����˯��״̬��
+// 对该缓冲块增加引用计数,并等待该缓冲块解锁(如果已被上锁)。由于经过了睡眠状态,
-// ����б�Ҫ����֤�û�������ȷ�ԣ������ػ����ͷָ�롣
+// 因此有必要再验证该缓冲块的正确性,并返回缓冲块头指针。
190 @@ -2750,7 +2750,7 @@ if (bh->b_dev == dev && bh->b_blocknr == block)
lang=EN-US> return bh; -// �����˯��ʱ�û�����������豸�Ż��ŷ����˸ı䣬�������������ü���������Ѱ�ҡ�
+// 如果在睡眠时该缓冲块所属的设备号或块号发生了改变,则撤消对它的引用计数,重新寻找。
194 @@ -2791,35 +2791,35 @@ lang=EN-US> */
/*
-* OK��������getblk�������ú������������Ǻ�������ͬ��Ҳ����ΪҪ����
+* OK,下面是getblk函数,该函数的逻辑并不是很清晰,同样也是因为要考虑
-* �����������⡣���дִ�������õ���(�����ظ��������)�������Ӧ��
+* 竞争条件问题。其中大部分代码很少用到,(例如重复操作语句),因此它应该
-* �ȿ���ȥ��������Ч�öࡣ
+* 比看上去的样子有效得多。
*
-* �㷨�Ѿ����˸ı䣺ϣ���ܸ��ã�����һ��������ĥ�Ĵ����Ѿ�ȥ����
+* 算法已经作了改变:希望能更好,而且一个难以琢磨的错误已经去除。
*/
-// ���������ͬʱ�жϻ��������ı�־��������־�����Ҷ����ı�־��Ȩ��Ҫ��������־
+// 下面宏用于同时判断缓冲区的修改标志和锁定标志,并且定义修改标志的权重要比锁定标志
-// ��
+// 大。
205 #define BADNESS(bh) (((bh)->b_dirt<<1)+(bh)->b_lock)
-//// ȡ���ٻ�����ָ���Ļ���顣
+//// 取高速缓冲中指定的缓冲块。
-// ���ָ�����豸�źͿ�ţ��Ļ������Ƿ��Ѿ��ڸ��ٻ����С����ָ�����Ѿ��ڸ��ٻ����У�
+// 检查指定(设备号和块号)的缓冲区是否已经在高速缓冲中。如果指定块已经在高速缓冲中,
-// �ض�Ӧ������ͷָ���˳���������ڣ�����Ҫ�ڸ��ٻ���������һ����Ӧ�豸�źͿ�ŵ�
+// 则返回对应缓冲区头指针退出;如果不在,就需要在高速缓冲中设置一个对应设备号和块号的
-// ���������Ӧ������ͷָ�롣
+// 新项。返回相应缓冲区头指针。
206 struct buffer_head *
210 repeat:
-// ����hash�������ָ�����Ѿ��ڸ��ٻ����У��ض�Ӧ������ͷָ�룬�˳���
+// 搜索hash表,如果指定块已经在高速缓冲中,则返回对应缓冲区头指针,退出。
211 if (bh = get_hash_table(dev,block))
lang=EN-US> return bh; -// ɨ��������ݿ�������Ѱ�ҿ��л�������
+// 扫描空闲数据块链表,寻找空闲缓冲区。
-// ������tmpָ����������ĵ�һ�����л�����ͷ��
+// 首先让tmp指向空闲链表的第一个空闲缓冲区头。
213 tmp = free_list;
214 do {
-// ����û���������ʹ�ã����ü���������0���������ɨ����һ�����b_count=0�Ŀ飬
+// 如果该缓冲区正被使用(引用计数不等于0),则继续扫描下一项。对于b_count=0的块,
-// �����ٻ����е�ǰû�����õĿ鲻һ�����Ǹɾ��ģ�b_dirt=0����û�������ģ�b_lock=0����
+// 即高速缓冲中当前没有引用的块不一定就是干净的(b_dirt=0)或没有锁定的(b_lock=0)。
-// ��ˣ����ǻ�����Ҫ����������жϺ�ѡ�����統һ�������д��һ�����ݺ���ͷ��ˣ�
+// 因此,我们还是需要继续下面的判断和选择。例如当一个任务改写过一块内容后就释放了,
-// ���Ǹÿ�b_count -= 0����b_lock������0����һ������ִ�� breada()Ԥ��������ʱ��ֻҪ
+// 于是该块b_count += 0,但b_lock不等于0;当一个任务执行 breada()预读几个块时,只要
-// ll_rw_block()����������ͻ�ݼ�b_count������ʱʵ����Ӳ�̷��ʲ������ܻ��ڽ��У�
+// ll_rw_block()命令发出后,它就会递减b_count;但此时实际上硬盘访问操作可能还在进行,
-// ��˴�ʱb_lock=1����b_count=0��
+// 因此此时b_lock=1,但b_count=0。
215 @@ -2885,17 +2885,17 @@ if (tmp->b_count)
lang=EN-US> continue; -// �������ͷָ��bhΪ�գ�����tmp��ָ����ͷ�ı�־(�ġ�����)Ȩ��С��bhͷ��־��Ȩ
+// 如果缓冲头指针bh为空,或者tmp所指缓冲头的标志(修改、锁定)权重小于bh头标志的权
-// �أ�����bhָ��tmp�����ͷ�� �����tmp�����ͷ����������û����Ҳû��������
+// 重,则让bh指向tmp缓冲块头。 如果该tmp缓冲块头表明缓冲块既没有修改也没有锁定标
-// ־��λ����˵����Ϊָ���豸�ϵĿ�ȡ�ö�Ӧ�ĸ��ٻ���飬���˳�ѭ�����������Ǿͼ���
+// 志置位,则说明已为指定设备上的块取得对应的高速缓冲块,则退出循环。否则我们就继续
-// ִ�б�ѭ���������ܷ��ҵ�һ��BADNESS()��С�Ļ���졣
+// 执行本循环,看看能否找到一个BADNESS()最小的缓冲快。
217
@@ -2920,18 +2920,18 @@ lang=EN-US> &nb
222 /* and repeat until we find something good */
-/* �ظ�����ֱ���ҵ��ʺϵĻ���� */
223 } while ((tmp = tmp->b_next_free) != free_list);
-// ���ѭ����鷢�����л���鶼���ڱ�ʹ�ã����л�����ͷ�����ü�����>0���У���˯��
+// 如果循环检查发现所有缓冲块都正在被使用(所有缓冲块的头部引用计数都>0)中,则睡眠
-// �ȴ��п��л������á����п��л�������ʱ�����̻ᱻ��ȷ�ػ��ѡ�Ȼ�����Ǿ���ת��
+// 等待有空闲缓冲块可用。当有空闲缓冲块可用时本进程会被明确地唤醒。然后我们就跳转到
-// ������ʼ�����²��ҿ��л���顣
+// 函数开始处重新查找空闲缓冲块。
224 if (!bh) {
@@ -2944,16 +2944,16 @@ blue'>buffer_wait);226 goto repeat; -// ��ת��210�С�
+// 跳转至210行。227 }
-// ִ�е����˵�������Ѿ��ҵ���һ���Ƚ��ʺϵĿ��л�����ˡ������ȵȴ��û���������
+// 执行到这里,说明我们已经找到了一个比较适合的空闲缓冲块了。于是先等待该缓冲区解锁
-//������ѱ������Ļ��������������˯�߽θû������ֱ���������ʹ�õĻ���ֻ���ظ�����
+//(如果已被上锁的话)。如果在我们睡眠阶段该缓冲区又被其他任务使用的话,只好重复上述
-// Ѱ�ҹ��̡�
+// 寻找过程。
228 wait_on_buffer(bh);
229 if (bh->b_count) -// �ֱ�ռ�ã���
+// 又被占用??230 goto repeat;
-// ����û������ѱ��ģ�������д�̣����ٴεȴ�������������ͬ���أ����û������ֱ�
+// 如果该缓冲区已被修改,则将数据写盘,并再次等待缓冲区解锁。同样地,若该缓冲区又被
-// ��������ʹ�õĻ���ֻ�����ظ�����Ѱ�ҹ��̡�
+// 其他任务使用的话,只好再重复上述寻找过程。
231 while
@@ -2986,7 +2986,7 @@ lang=EN-US> &nb
234
if (bh->b_count)
-// �ֱ�ռ�ã���
235 @@ -3003,15 +3003,15 @@ else might */
lang=EN-US> /* already have added "this" block to the cache. check it */ -/* ע�⣡��������Ϊ�˵ȴ��û�����˯��ʱ���������̿����Ѿ����û���� /* 注意!!当进程为了等待该缓冲块而睡眠时,其他进程可能已经将该缓冲块 */
-* ��������ٻ����У���������ҲҪ�Դ˽��м�顣 * 加入进高速缓冲中,所以我们也要对此进行检查。*/
-// �ڸ��ٻ���hash���м��ָ���豸�Ϳ�Ļ�����Ƿ������˯��֮���Ѿ��������ȥ�����
+// 在高速缓冲hash表中检查指定设备和块的缓冲块是否乘我们睡眠之即已经被加入进去。如果
-// �ǵĻ������ٴ��ظ�����Ѱ�ҹ��̡�
+// 是的话,就再次重复上述寻找过程。
239 if (
lang=EN-US> /* and that it's unused (b_count=0), unlocked (b_lock=0), and clean */ -/* OK����������֪���û������ָ��������Ψһһ�飬����Ŀǰ��û�б�ռ�� /* OK,最终我们知道该缓冲块是指定参数的唯一一块,而且目前还没有被占用 */
-/* (b_count=0)��Ҳδ������(b_lock=0)�������Ǹɾ��ģ�δ���ĵģ�*/
+/* (b_count=0),也未被上锁(b_lock=0),并且是干净的(未被修改的)*/
-// ����������ռ�ô˻���顣�����ü���Ϊ1����λ�ı�־����Ч(����)��־��
+// 于是让我们占用此缓冲块。置引用计数为1,复位修改标志和有效(更新)标志。
243 bh->b_count=1;
@@ -3047,12 +3047,12 @@ lang=EN-US> bh->b_dirt=0;245 bh->b_uptodate=0; -// ��hash���кͿ��п��������Ƴ��û�����ͷ���øû���������ָ���豸�����ϵ�ָ���顣
+// 从hash队列和空闲块链表中移出该缓冲区头,让该缓冲区用于指定设备和其上的指定块。
-// Ȼ����ݴ��µ��豸�źͿ�����²������������hash������λ�ô��������շ��ػ���
+// 然后根据此新的设备号和块号重新插入空闲链表和hash队列新位置处。并最终返回缓冲
-// ͷָ�롣
+// 头指针。
246 }
252
-//// �ͷ�ָ������顣
+//// 释放指定缓冲块。
-// �ȴ��û���������Ȼ�����ü����ݼ�1������ȷ�ػ��ѵȴ����л����Ľ��̡�
+// 等待该缓冲块解锁。然后引用计数递减1,并明确地唤醒等待空闲缓冲块的进程。
253 void brelse(struct {
255 if (!buf) -// �������ͷָ����Ч�ء�
+// 如果缓冲头指针无效则返回。256 @@ -3137,21 +3137,21 @@ lang=EN-US> */
/*
-* ���豸�϶�ȡָ�������ݿ鲢���غ������ݵĻ����������ָ���Ŀ鲻����
+* 从设备上读取指定的数据块并返回含有数据的缓冲区。如果指定的块不存在
-* ��NULL��
+* 则返回NULL。
*/
-//// ���豸�϶�ȡ���ݿ顣
+//// 从设备上读取数据块。
-// �ú�������ָ�����豸��dev�����ݿ��block�������ڸ��ٻ�����������һ�黺��顣
+// 该函数根据指定的设备号dev和数据块号block,首先在高速缓冲区中申请一块缓冲块。
-// ����û�������Ѿ���������Ч�����ݾ�ֱ�ӷ��ظû����ָ�룬����ʹ��豸�ж�ȡ
+// 如果该缓冲块中已经包含有有效的数据就直接返回该缓冲块指针,否则就从设备中读取
-// ָ�������ݿ鵽�û�����в����ػ����ָ�롣
+// 指定的数据块到该缓冲块中并返回缓冲块指针。
267 struct buffer_head * buffer_head * bh;
270
-// �ڸ��ٻ�����������һ�黺��顣�������ֵ��NULL�����ʾ�ں˳�����ͣ����Ȼ������
+// 在高速缓冲区中申请一块缓冲块。如果返回值是NULL,则表示内核出错,停机。然后我们
-// �ж������Ƿ����п������ݡ� ����û��������������Ч�ģ��Ѹ��µģ�����ֱ��ʹ�ã�
+// 判断其中是否已有可用数据。 如果该缓冲块中数据是有效的(已更新的)可以直接使用,
-// �ء�
+// 则返回。
271 if (!(bh= if lang=EN-US> return bh;
-// �������Ǿ͵��õײ���豸��дll_rw_block()�������������豸������Ȼ��ȴ�ָ��
+// 否则我们就调用底层块设备读写ll_rw_block()函数,产生读设备块请求。然后等待指定
-// ���ݿ鱻���룬���ȴ���������������˯������֮������û������Ѹ��£��ػ���
+// 数据块被读入,并等待缓冲区解锁。在睡眠醒来之后,如果该缓冲区已更新,则返回缓冲
-// ��ͷָ�룬�˳�������������豸����ʧ�ܣ������ͷŸû�����������NULL���˳���
+// 区头指针,退出。否则表明读设备操作失败,于是释放该缓冲区,返回NULL,退出。
275 }
282
-//// �����ڴ�顣
+//// 复制内存块。
-// ��from��ַ����һ�飨1024�ֽڣ����ݵ�toλ�á�
+// 从from地址复制一块(1024字节)数据到to位置。
283 #define COPYBLK(from,to) \
@@ -3282,22 +3282,22 @@ lang=EN-US> *//*
-* bread_pageһ�ζ��ĸ���������ݶ����ڴ�ָ���ĵ�ַ��������һ�������ĺ����� +
* bread_page一次读四个缓冲块数据读到内存指定的地址处。它是一个完整的函数,
-* ��Ϊͬʱ��ȡ�Ŀ���Ի���ٶ��ϵĺô������õ��Ŷ�һ�飬�ٶ�һ���ˡ�
+* 因为同时读取四块可以获得速度上的好处,不用等着读一块,再读一块了。
*/
-//// ���豸��һ��ҳ�棨4������飩�����ݵ�ָ���ڴ��ַ����
+//// 读设备上一个页面(4个缓冲块)的内容到指定内存地址处。
-// ����address�DZ���ҳ�����ݵĵ�ַ��dev��ָ�����豸�ţ�b[4]�Ǻ���4���豸���ݿ��
+// 参数address是保存页面数据的地址;dev是指定的设备号;b[4]是含有4个设备数据块号
-// �����顣�ú���������mm/memory.c�ļ���do_no_page()�����У���386�У���
+// 的数组。该函数仅用于mm/memory.c文件的do_no_page()函数中(第386行)。
296 void bread_page(unsigned @@ -3316,19 +3316,19 @@ lang=EN-US> int i;
300
-// �ú���ѭ��ִ��4�Σ����ݷ�������b[]�е�4����Ŵ��豸dev�ж�ȡһҳ���ݷŵ�ָ��
+// 该函数循环执行4次,根据放在数组b[]中的4个块号从设备dev中读取一页内容放到指定
-// �ڴ�λ�� -address���� ���ڲ���b[i]��������Ч��ţ��������ȴӸ��ٻ�����ȡָ���豸
+// 内存位置 +address处。 对于参数b[i]给出的有效块号,函数首先从高速缓冲中取指定设备
-// �Ϳ�ŵĻ���顣����������������Ч��δ���£���������豸������豸�϶�ȡ��Ӧ��
+// 和块号的缓冲块。如果缓冲块中数据无效(未更新)则产生读设备请求从设备上读取相应数
-// �ݿ顣����b[i]��Ч�Ŀ������ȥ�����ˡ���˱�������ʵ���Ը���ָ����b[]�еĿ��
+// 据块。对于b[i]无效的块号则不用去理它了。因此本函数其实可以根据指定的b[]中的块号
-// �����ȡ1��4�����ݿ顣
+// 随意读取1—4个数据块。
301 for (i=0 ; i<4 ; @@ -3337,7 +3337,7 @@ i++)
302 if (b[i]) { -// ���������
+// 若块号有效。303 @@ -3359,11 +3359,11 @@ lang=EN-US> &nb lang=EN-US> bh[i] = NULL;
-// ���4��������ϵ�����˳���Ƶ�ָ����ַ�����ڽ��и��ƣ�ʹ�ã������֮ǰ����
+// 随后将4个缓冲块上的内容顺序复制到指定地址处。在进行复制(使用)缓冲块之前我们
-// ��Ҫ˯�ߵȴ��������������������Ļ��������⣬��Ϊ����˯�߹��ˣ��������ǻ���Ҫ
+// 先要睡眠等待缓冲块解锁(若被上锁的话)。另外,因为可能睡眠过了,所以我们还需要
-// �ڸ���֮ǰ�ټ��һ�»�����е������Ƿ�����Ч�ġ�����������ǻ���Ҫ�ͷŻ���顣
+// 在复制之前再检查一下缓冲块中的数据是否是有效的。复制完后我们还需要释放缓冲块。
308 for (i=0 ; i<4 ; @@ -3375,12 +3375,12 @@ if (bh[i]) {
310 -wait_on_buffer(bh[i]); // �ȴ���������(���������Ļ�)��
+wait_on_buffer(bh[i]); // 等待缓冲块解锁(若被上锁的话)。311 -if (bh[i]->b_uptodate) // ���������������Ч�Ļ����ơ�
+if (bh[i]->b_uptodate) // 若缓冲块中数据有效的话则复制。312 @@ -3390,7 +3390,7 @@ bh[i]->b_data,address);
313 brelse(bh[i]); -// �ͷŸû�������
+// 释放该缓冲区。314 @@ -3421,19 +3421,19 @@ lang=EN-US> */
/*
-* OK��breada������breadһ��ʹ�ã���������Ԥ��һЩ�顣�ú��������б�
+* OK,breada可以象bread一样使用,但会另外预读一些块。该函数参数列表
-* ��Ҫʹ��һ�����������������б��Ľ�����
+* 需要使用一个负数来表明参数列表的结束。
*/
-//// ��ָ���豸��ȡָ����һЩ�顣
+//// 从指定设备读取指定的一些块。
-// �������������ɱ䣬��һϵ��ָ���Ŀ�š��ɹ�ʱ���ص�1��Ļ����ͷָ�룬����
+// 函数参数个数可变,是一系列指定的块号。成功时返回第1块的缓冲块头指针,否则返回
-// NULL��
+// NULL。
322 struct buffer_head * buffer_head * bh, *tmp;
326
-// ����ȡ�ɱ�������е�1����������ţ������ŴӸ��ٻ�������ȡָ���豸�Ϳ�ŵĻ���
+// 首先取可变参数表中第1个参数(块号)。接着从高速缓冲区中取指定设备和块号的缓冲
-// �顣����û����������Ч�����±�־δ��λ���������豸���ݿ�����
+// 块。如果该缓冲块数据无效(更新标志未置位),则发出读设备数据块请求。
327 if lang=EN-US> ll_rw_block(READ,bh);
-// Ȼ��˳��ȡ�ɱ������������Ԥ����ţ�����������ͬ���������������á�ע�⣬336����
+// 然后顺序取可变参数表中其他预读块号,并作与上面同样处理,但不引用。注意,336行上
-// ��һ��bug�����е�bhӦ����tmp�����bugֱ����0.96����ں˴����вű�����������
+// 有一个bug。其中的bh应该是tmp。这个bug直到在0.96版的内核代码中才被纠正过来。
-// ���⣬��Ϊ������Ԥ���������ݿ飬ֻ��������ٻ��������������Ͼ�ʹ�ã����Ե� // 另外,因为这里是预读随后的数据块,只需读进高速缓冲区但并不马上就使用,所以第337
-// �������Ҫ�������ü����ݼ��ͷŵ��ÿ飨��Ϊgetblk()���������ӻ�������ü���ֵ����
+// 行语句需要将其引用计数递减释放掉该块(因为getblk()函数会增加缓冲块引用计数值)。
332 while ((first=
336 ll_rw_block(READA,bh); -// bh Ӧ����tmp��
+// bh 应该是tmp。337 tmp->b_count--; - // ��ʱ�ͷŵ���Ԥ���顣
+ // 暂时释放掉该预读块。338
@@ -3525,12 +3525,12 @@ lang=EN-US> &nb
339 } // ��ʱ�ɱ�����������в���������ϡ����ǵȴ���1������������������ѱ����������ڵ� // 此时可变参数表中所有参数处理完毕。于是等待第1个缓冲区解锁(如果已被上锁)。在等 // ���˳�֮�������������������Ȼ��Ч���ػ�����ͷָ���˳��������ͷŸû��������� // 待退出之后如果缓冲区中数据仍然有效,则返回缓冲区头指针退出。否则释放该缓冲区返回 // NULL���˳��� // NULL,退出。 340 } 347 //// ��������ʼ�������� //// 缓冲区初始化函数。 // ����buffer_end�ǻ������ڴ�ĩ�ˡ����ھ���16MB�ڴ��ϵͳ��������ĩ�˱�����Ϊ4MB�� // 参数buffer_end是缓冲区内存末端。对于具有16MB内存的系统,缓冲区末端被设置为4MB。 // ������8MB�ڴ��ϵͳ��������ĩ�˱�����Ϊ2MB���ú����ӻ�������ʼλ��start_buffer // 对于有8MB内存的系统,缓冲区末端被设置为2MB。该函数从缓冲区开始位置start_buffer // ���ͻ�����ĩ��buffer_end���ֱ�ͬʱ���ã���ʼ���������ͷ�ṹ�Ͷ�Ӧ�����ݿ顣ֱ�� // 处和缓冲区末端buffer_end处分别同时设置(初始化)缓冲块头结构和对应的数据块。直到 // �������������ڴ汻������ϡ��μ������б�ǰ���ʾ��ͼ�� // 缓冲区中所有内存被分配完毕。参见程序列表前面的示意图。 348 void buffer_init(long
@@ -3595,14 +3595,14 @@ lang=EN-US> int i; 353 // ���ȸ��ݲ����ṩ�Ļ������߶�λ��ȷ��ʵ�ʻ������߶�λ��b������������߶˵���1Mb�� // 首先根据参数提供的缓冲区高端位置确定实际缓冲区高端位置b。如果缓冲区高端等于1Mb, // ����Ϊ��640KB
-- 1MB����ʾ�ڴ�� BIOSռ�ã�����ʵ�ʿ��û������ڴ�߶�λ��Ӧ���� // 则因为从640KB
+- 1MB被显示内存和 BIOS占用,所以实际可用缓冲区内存高端位置应该是 // 640KB���������ڴ�߶�һ������1MB�� // 640KB。否则缓冲区内存高端一定大于1MB。 354 if (buffer_end ==
@@ -3619,22 +3619,22 @@ lang=EN-US> else
// ��δ������ڳ�ʼ�����������������л����ѭ������������ȡϵͳ�л������Ŀ��������
+// 这段代码用于初始化缓冲区,建立空闲缓冲块循环链表,并获取系统中缓冲块数目。操作的
-// �����Ǵӻ������߶˿�ʼ����1KB��С�Ļ���飬���ͬʱ�ڻ������Ͷ˽��������û����
+// 过程是从缓冲区高端开始划分1KB大小的缓冲块,与此同时在缓冲区低端建立描述该缓冲块
-// �Ľṹbuffer_head��������Щbuffer_head���˫��������
+// 的结构buffer_head,并将这些buffer_head组成双向链表。
-// h��ָ��ͷ�ṹ��ָ�룬��h+1��ָ���ڴ��ַ��������һ������ͷ��ַ��Ҳ����˵��
+// h是指向缓冲头结构的指针,而h+1是指向内存地址连续的下一个缓冲头地址,也可以说是
-// ָ��h����ͷ��ĩ���⡣Ϊ�˱�֤���㹻���ȵ��ڴ����洢һ������ͷ�ṹ����Ҫb��ָ��
+// 指向h缓冲头的末端外。为了保证有足够长度的内存来存储一个缓冲头结构,需要b所指向
-// ���ڴ���ַ >= h����ͷ��ĩ�ˣ���Ҫ�� >= h+1��
+// 的内存块地址 >= h缓冲头的末端,即要求 >= h+1。
358 while ( (b -= BLOCK_SIZE) >= ((void *) (h+1)) ) {
359 h->b_dev = 0; -// ʹ�øû������豸�š�
+// 使用该缓冲块的设备号。360 h->b_dirt = 0; -// ���־����������ı�־��
+// 脏标志,即缓冲块修改标志。361 h->b_count = 0; -// ��������ü�����
+// 缓冲块引用计数。362 h->b_lock = 0; -// �����������־��
+// 缓冲块锁定标志。363 -h->b_uptodate = 0; // �������±�־�����������Ч��־����
+h->b_uptodate = 0; // 缓冲块更新标志(或称数据有效标志)。364 h->b_wait = NULL; -// ָ��ȴ��û��������Ľ��̡�
+// 指向等待该缓冲块解锁的进程。365 h->b_next = NULL; -// ָ�������ͬhashֵ����һ������ͷ��
+// 指向具有相同hash值的下一个缓冲头。366 h->b_prev = NULL; -// ָ�������ͬhashֵ��ǰһ������ͷ��
+// 指向具有相同hash值的前一个缓冲头。367 -h->b_data = (char *) b; // ָ���Ӧ��������ݿ飨1024�ֽڣ���
+h->b_data = (char *) b; // 指向对应缓冲块数据块(1024字节)。368 -h->b_prev_free = h-1; // ָ��������ǰһ�
+h->b_prev_free = h-1; // 指向链表中前一项。369 -h->b_next_free = h+1; // ָ����������һ�
+h->b_next_free = h+1; // 指向链表中下一项。370 h++; -// hָ����һ�»���ͷλ�á�
+// h指向下一新缓冲头位置。371 NR_BUFFERS++; -// �����������ۼӡ�
+// 缓冲区块数累加。372 -if (b == (void *) 0x100000) // ��b�ݼ�������1MB��������384KB��
+if (b == (void *) 0x100000) // 若b递减到等于1MB,则跳过384KB,373 -b = (void *) 0xA0000; // ��bָ���ַ0xA0000(640KB)����
+b = (void *) 0xA0000; // 让b指向地址0xA0000(640KB)处。374 }
375 h--; -// ��hָ�����һ����Ч�����ͷ��
+// 让h指向最后一个有效缓冲块头。376 free_list = start_buffer; -// �ÿ�������ͷָ��ͷһ������顣
+// 让空闲链表头指向头一个缓冲块。377 free_list->b_prev_free = h; // ����ͷ��b_prev_freeָ��ǰһ������һ���
+style='color:blue'>free_list->b_prev_free = h; // 链表头的b_prev_free指向前一项(即最后一项)。378 h->b_next_free = free_list; -// h����һ��ָ��ָ���һ��γ�һ��������
+// h的下一项指针指向第一项,形成一个环链。 -// ����ʼ��hash������ϣ����ɢ�б������ñ�������ָ��ΪNULL��
+// 最后初始化hash表(哈希表、散列表),置表中所有指针为NULL。
379 for (i=0;i<
-
6 7
-#include <signal.h> // �ź�ͷ�ļ��������źŷ��ų������źŽṹ����������ԭ�͡� 8
-#include <errno.h> // �����ͷ�ļ�������ϵͳ�и��ֳ����š� 9
-#include <termios.h> // �ն������������ͷ�ļ�����Ҫ��������첽ͨ�ſڵ��ն˽ӿڡ� 10 11
-#include <linux/sched.h> // ���ȳ���ͷ�ļ�������������ṹtask_struct������0���ݵȡ� 12
#include <linux/mm.h> /* for get_free_page */
-/* ʹ�����е�get_free_page */ 13
-#include <asm/segment.h> // �β���ͷ�ļ����������йضμĴ���������Ƕ��ʽ��ຯ���� 14
-#include <linux/kernel.h> // �ں�ͷ�ļ�������һЩ�ں˳��ú�����ԭ�ζ��塣 15 //// �ܵ������������� //// 管道读操作函数。 // ����inode�ǹܵ���Ӧ��i�ڵ㣬buf���û����ݻ�����ָ�룬count�Ƕ�ȡ���ֽ����� // 参数inode是管道对应的i节点,buf是用户数据缓冲区指针,count是读取的字节数。 16 int
read_pipe(struct read = 0; 19 // �����Ҫ��ȡ���ֽڼ���count����0�����Ǿ�ѭ��ִ�����²�������ѭ�������������У� // 如果需要读取的字节计数count大于0,我们就循环执行以下操作。在循环读操作过程中, // ����ǰ�ܵ���û�����ݣ�size=0�������ѵȴ��ýڵ�Ľ��̣���ͨ����д�ܵ����̡���� // 若当前管道中没有数据(size=0),则唤醒等待该节点的进程,这通常是写管道进程。如果 // ��û��д�ܵ��ߣ��� i�ڵ����ü���ֵС��2�����Ѷ��ֽ����˳��������ǰ�յ��з� // 已没有写管道者,即 i节点引用计数值小于2,则返回已读字节数退出。如果当前收到有非 // �����źţ������̷����Ѷ�ȡ�ֽ����˳�������û���յ��κ����ݣ�����������ϵͳ // 阻塞信号,则立刻返回已读取字节数退出;若还没有收到任何数据,则返回重新启动系统 // ���ú��˳���������ý����ڸùܵ���˯�ߣ����Եȴ���Ϣ�ĵ�������PIPE_SIZE������ // 调用号退出。否则就让进程在该管道上睡眠,用以等待信息的到来。宏PIPE_SIZE定义在 // include/linux/fs.h�С����ڡ���������ϵͳ���á�����μ�kernel/signal.c���� // include/linux/fs.h中。关于“重新启动系统调用”,请参见kernel/signal.c程序。 20
while (count>0) { 21
while (!(size=PIPE_SIZE(*inode))) {
- // ȡ�ܵ������ݳ���ֵ�� 22
wake_up(& PIPE_READ_WAIT(*inode)); 28
} // ��ʱ˵���ܵ������������������ݡ���������ȡ�ܵ�βָ�뵽������ĩ�˵��ֽ���chars�� // 此时说明管道(缓冲区)中有数据。于是我们取管道尾指针到缓冲区末端的字节数chars。 // �������ڻ���Ҫ��ȡ���ֽ���count�����������count�����chars���ڵ�ǰ�ܵ��к� // 如果其大于还需要读取的字节数count,则令其等于count。如果chars大于当前管道中含 // �����ݵij��� size����������� size�� Ȼ�������ֽ���count��ȥ�˴οɶ����ֽ��� // 有数据的长度 size,则令其等于 size。 然后把需读字节数count减去此次可读的字节数 // chars�����ۼ��Ѷ��ֽ���read�� // chars,并累加已读字节数read。 29
chars = PAGE_SIZE-count -= chars; 35
read += chars; // ����sizeָ��ܵ�βָ�봦����������ǰ�ܵ�βָ�루ǰ��chars�ֽڣ�����βָ�볬�� // 再令size指向管道尾指针处,并调整当前管道尾指针(前移chars字节)。若尾指针超过 // �ܵ�ĩ�����ƻء�Ȼ�ܵ��е����ݸ��Ƶ��û��������С����ڹܵ�i�ڵ㣬��i_size // 管道末端则绕回。然后将管道中的数据复制到用户缓冲区中。对于管道i节点,其i_size // �ֶ����ǹܵ������ָ�롣 // 字段中是管道缓冲块指针。 36
size = PIPE_TAIL(*inode); 41
} // ���˴ζ��ܵ��������������ѵȴ��ùܵ��Ľ��̣������ض�ȡ���ֽ����� // 当此次读管道操作结束,则唤醒等待该管道的进程,并返回读取的字节数。 42
wake_up(& read; 45
//// �ܵ�д���������� //// 管道写操作函数。 // ����inode�ǹܵ���Ӧ��i�ڵ㣬buf�����ݻ�����ָ�룬count�ǽ�д��ܵ����ֽ����� // 参数inode是管道对应的i节点,buf是数据缓冲区指针,count是将写入管道的字节数。 46 int
write_pipe(struct 49 // ���Ҫд����ֽ���count������0����ô���Ǿ�ѭ��ִ�����²�������ѭ�����������У� // 如果要写入的字节数count还大于0,那么我们就循环执行以下操作。在循环操作过程中, // �����ǰ�ܵ����Ѿ����ˣ����пռ� size = 0�������ѵȴ��ùܵ��Ľ��̣�ͨ������ // 如果当前管道中已经满了(空闲空间 size = 0),则唤醒等待该管道的进程,通常唤醒 // ���Ƕ��ܵ����̡� �����û�ж��ܵ��ߣ���i�ڵ����ü���ֵС��2������ǰ���̷��� // 的是读管道进程。 如果已没有读管道者,即i节点引用计数值小于2,则向当前进程发送 // SIGPIPE�źţ���������д����ֽ����˳�����д��0�ֽڣ��� -1�������õ�ǰ���� // SIGPIPE信号,并返回已写入的字节数退出;若写入0字节,则返回 -1。否则让当前进程 // �ڸùܵ���˯�ߣ��Եȴ����ܵ���������ȡ���ݣ��Ӷ��ùܵ��ڳ��ռ䡣��PIPE_SIZE()�� // 在该管道上睡眠,以等待读管道进程来读取数据,从而让管道腾出空间。宏PIPE_SIZE()、 // PIPE_HEAD()�ȶ������ļ�include/linux/fs.h�С� // PIPE_HEAD()等定义在文件include/linux/fs.h中。 50
while (count>0) { 58
} // ����ִ�е������ʾ�ܵ����������п�д�ռ�size����������ȡ�ܵ�ͷָ�뵽������ĩ�˿� // 程序执行到这里表示管道缓冲区中有可写空间size。于是我们取管道头指针到缓冲区末端空 // ���ֽ���chars��д�ܵ������Ǵӹܵ�ͷָ�봦��ʼд�ġ����chars���ڻ���Ҫд����ֽ� // 间字节数chars。写管道操作是从管道头指针处开始写的。如果chars大于还需要写入的字节 // ��count����������� count�� ��� chars���ڵ�ǰ�ܵ��п��пռ䳤��size����������� // 数count,则令其等于 count。 如果 chars大于当前管道中空闲空间长度size,则令其等于 // size��Ȼ�����Ҫд���ֽ���count��ȥ�˴ο�д����ֽ���chars������д���ֽ����ۼӵ� // size。然后把需要写入字节数count减去此次可写入的字节数chars,并把写入字节数累加到 // written�С� // written中。 59
chars = PAGE_SIZE- 65
written += chars; // ����sizeָ��ܵ�����ͷָ�봦����������ǰ�ܵ�����ͷ��ָ�루ǰ��chars�ֽڣ�����ͷ // 再令size指向管道数据头指针处,并调整当前管道数据头部指针(前移chars字节)。若头 // ָ�볬���ܵ�ĩ�����ƻء�Ȼ����û�����������chars���ֽڵ��ܵ�ͷָ�뿪ʼ���� ���� // 指针超过管道末端则绕回。然后从用户缓冲区复制chars个字节到管道头指针开始处。 对于 // �ܵ�i�ڵ㣬��i_size�ֶ����ǹܵ������ָ�롣 // 管道i节点,其i_size字段中是管道缓冲块指针。 66
size = PIPE_HEAD(*inode); 71
} // ���˴�д�ܵ��������������ѵȴ��ܵ��Ľ��̣�������д����ֽ������˳��� // 当此次写管道操作结束,则唤醒等待管道的进程,返回已写入的字节数,退出。 72
wake_up(& 75 //// �����ܵ�ϵͳ���á� //// 创建管道系统调用。 // ��fildes��ָ�������д���һ���ļ��������������������ļ����ָ��һ�ܵ�i�ڵ㡣 // 在fildes所指的数组中创建一对文件句柄(描述符)。这对文件句柄指向一管道i节点。 // ������filedes
--�ļ�������顣fildes[0]���ڶ��ܵ����ݣ�fildes[1]��ܵ�д�����ݡ� // 参数:filedes
+-文件句柄数组。fildes[0]用于读管道数据,fildes[1]向管道写入数据。 // �ɹ�ʱ����0������ʱ����-1�� // 成功时返回0,出错时返回-1。 76 int
sys_pipe(unsigned long * fildes) 79
struct file * f[2];
-// �ļ��ṹ���顣 80
int fd[2];
-// �ļ�������顣 81
int i,j; 82 // ���ȴ�ϵͳ�ļ�����ȡ������������ü����ֶ�Ϊ0��������ֱ��������ü���Ϊ1�� // 首先从系统文件表中取两个空闲项(引用计数字段为0的项),并分别设置引用计数为1。 // ��ֻ��1����������ͷŸ�����ü�����λ������û���ҵ������������ -1�� // 若只有1个空闲项,则释放该项(引用计数复位)。若没有找到两个空闲项,则返回 -1。 83
j=0; 90
return -1; // �������ȡ�õ������ļ����ṹ��ֱ����һ�ļ�����ţ���ʹ�����ļ��ṹָ������� // 针对上面取得的两个文件表结构项,分别分配一文件句柄号,并使进程文件结构指针数组的 // ����ֱ�ָ���������ļ��ṹ�����ļ�������Ǹ�����������š����Ƶأ����ֻ��һ���� // 两项分别指向这两个文件结构。而文件句柄即是该数组的索引号。类似地,如果只有一个空 // ���ļ���������ͷŸþ�����ÿ���Ӧ����������û���ҵ��������о�������ͷ����� // 闲文件句柄,则释放该句柄(置空相应数组项)。如果没有找到两个空闲句柄,则释放上面 // ��ȡ�������ļ��ṹ���λ���ü���ֵ���������� -1�� // 获取的两个文件结构项(复位引用计数值),并返回 -1。 91
j=0; 102 } // Ȼ�����ú���get_pipe_inode()����һ���ܵ�ʹ�õ�i�ڵ㣬��Ϊ�ܵ�����һҳ�ڴ���Ϊ�� // 然后利用函数get_pipe_inode()申请一个管道使用的i节点,并为管道分配一页内存作为缓 // ������������ɹ�������Ӧ�ͷ������ļ�������ļ��ṹ�������-1�� // 冲区。如果不成功,则相应释放两个文件句柄和文件结构项,并返回-1。 103 if (!(inode=get_pipe_inode())) {
- // fs/inode.c����231�п�ʼ���� 104
@@ -2306,14 +2306,14 @@ return -1; 108 } // ����ܵ�i�ڵ�����ɹ�����������ļ��ṹ���г�ʼ�������������Ƕ�ָ��ͬһ���ܵ�i�� // 如果管道i节点申请成功,则对两个文件结构进行初始化操作,让它们都指向同一个管道i节 // �㣬���Ѷ�дָ�붼���㡣��1���ļ��ṹ���ļ�ģʽ��Ϊ������2���ļ��ṹ���ļ�ģʽ�� // 点,并把读写指针都置零。第1个文件结构的文件模式置为读,第2个文件结构的文件模式置 // Ϊд������ļ�������鸴�Ƶ���Ӧ���û��ռ������У��ɹ�����0���˳��� // 为写。最后将文件句柄数组复制到对应的用户空间数组中,成功返回0,退出。 109 f[0]->f_inode =
@@ -2350,13 +2350,13 @@ lang=EN-US> } 117 //// �ܵ�io���ƺ����� //// 管道io控制函数。 // ������pino
-- �ܵ�i�ڵ�ָ�룻cmd - �������arg - ������ // 参数:pino
+- 管道i节点指针;cmd - 控制命令;arg - 参数。 // ��������0��ʾִ�гɹ������س����롣 // 函数返回0表示执行成功,否则返回出错码。 118 int pipe_ioctl(struct m_inode *pino, int cmd, int arg) 119 { // ���������ȡ�ܵ��е�ǰ�ɶ����ݳ��ȣ���ѹܵ����ݳ���ֵ�����û�����ָ����λ�ô��� // 如果命令是取管道中当前可读数据长度,则把管道数据长度值添入用户参数指定的位置处, // ������0��������Ч��������롣 // 并返回0。否则返回无效命令错误码。 120 switch (cmd) { ����程序12-11 linux/fs/char_dev.c 6 7
-#include <errno.h> // �����ͷ�ļ�������ϵͳ�и��ֳ����š� 8
-#include <sys/types.h> // ����ͷ�ļ��������˻�����ϵͳ�������͡� 9 10
-#include <linux/sched.h> // ���ȳ���ͷ�ļ�����������ṹtask_struct������0���ݵȡ� 11
-#include <linux/kernel.h> // �ں�ͷ�ļ�������һЩ�ں˳��ú�����ԭ�ζ��塣 12 13
-#include <asm/segment.h> // �β���ͷ�ļ����������йضμĴ���������Ƕ��ʽ��ຯ���� 14
-#include <asm/io.h> // ioͷ�ļ�������Ӳ���˿�����/���������䡣 15 16
extern int tty_read(unsigned minor,char
* buf,int count);
-// �ն˶��� 17
extern int tty_write(unsigned minor,char
* buf,int count);
-// �ն�д�� 18 // �����ַ��豸��д����ָ�����͡� // 定义字符设备读写函数指针类型。 19
typedef (*crw_ptr)(int rw,unsigned
@@ -1895,15 +1895,15 @@ style='color:blue'>count,off_t
20 //// �����ն˶�д���������� //// 串口终端读写操作函数。 // ������rw
-- ��д���minor - �ն����豸�ţ�buf - ��������cout - ��д�ֽ����� // 参数:rw
+- 读写命令;minor - 终端子设备号;buf - 缓冲区;cout - 读写字节数; // pos - ��д������ǰָ�룬�����ն˲�������ָ�����á� // pos - 读写操作当前指针,对于终端操作,该指针无用。 // ���أ�ʵ�ʶ�д���ֽ�������ʧ���س����롣 // 返回:实际读写的字节数。若失败则返回出错码。 21
static int rw_ttyx(int rw,unsigned
@@ -1926,9 +1926,9 @@ style='color:blue'>buf,count))
26 //// �ն˶�д���������� //// 终端读写操作函数。 // ͬ��rw_ttyx()��ֻ�������˶Խ����Ƿ��п����ն˵ļ�⡣ // 同上rw_ttyx(),只是增加了对进程是否有控制终端的检测。 27
static int rw_tty(int rw,unsigned
@@ -1938,10 +1938,10 @@ style='color:blue'>count, off_t 28 { // ������û�ж�Ӧ�Ŀ����նˣ��س����š���������ն˶�д����rw_ttyx()�������� // 若进程没有对应的控制终端,则返回出错号。否则调用终端读写函数rw_ttyx(),并返回 // ʵ�ʶ�д�ֽ����� // 实际读写字节数。 29
if (current->tty<0) 33 //// �ڴ����ݶ�д��δʵ�֡� //// 内存数据读写。未实现。 34
static int rw_ram(int rw,char * EIO; 38 //// �����ڴ����ݶ�д����������δʵ�֡� //// 物理内存数据读写操作函数。未实现。 39
static int rw_mem(int rw,char * EIO; 43 //// �ں������ڴ����ݶ�д������δʵ�֡� //// 内核虚拟内存数据读写函数。未实现。 44
static int rw_kmem(int rw,char * EIO; 48 // �˿ڶ�д���������� // 端口读写操作函数。 // ������rw
-- ��д���buf - ��������cout - ��д�ֽ�����pos - �˿ڵ�ַ�� // 参数:rw
+- 读写命令;buf - 缓冲区;cout - 读写字节数;pos - 端口地址。 // ���أ�ʵ�ʶ�д���ֽ����� // 返回:实际读写的字节数。 49
static int rw_port(int rw,char * pos; 52 // ������Ҫ���д���ֽ��������Ҷ˿ڵ�ַС��64kʱ��ѭ��ִ�е����ֽڵĶ�д������ // 对于所要求读写的字节数,并且端口地址小于64k时,循环执行单个字节的读写操作。 // ���Ƕ������Ӷ˿�i�ж�ȡһ�ֽ����ݲ��ŵ��û��������С�����д�������� // 若是读命令,则从端口i中读取一字节内容并放到用户缓冲区中。若是写命令,则从用 // �����ݻ�������ȡһ�ֽ�������˿�i�� // 户数据缓冲区中取一字节输出到端口i。 53
while (count-->0 &&
@@ -2055,13 +2055,13 @@ style='color:blue'>buf++),i); 58
i++;
-// ǰ��һ���˿ڡ�[??] 59
} // Ȼ������/д���ֽ�����������Ӧ��дָ�룬�����ض�/д���ֽ����� // 然后计算读/写的字节数,调整相应读写指针,并返回读/写的字节数。 60
i -= *pos; 64 //// �ڴ��д�����������ڴ����豸����1�������������0-5���豸�Ĵ����� //// 内存读写操作函数。内存主设备号是1。这里仅给出对0-5子设备的处理。 65
static int rw_memory(int rw, unsigned
@@ -2087,14 +2087,14 @@ style='color:blue'>count, off_t 66 { // �����ڴ��豸���豸�ţ��ֱ���ò�ͬ���ڴ��д������ // 根据内存设备子设备号,分别调用不同的内存读写函数。 67
switch(minor) { 68
-case 0: // ��Ӧ�豸�ļ����� /dev/ram0��/dev/ramdisk�� 69
return rw_ram(rw,buf,count,<
style='color:blue'>pos); 70
-case 1: // /dev/ram1��/dev/mem��ram�� 71
return rw_mem(rw,buf,count,<
style='color:blue'>pos); 72
-case 2: // /dev/ram2��/dev/kmem�� 73
return rw_kmem(rw,buf,count,<
style='color:blue'>pos); 74
-case 3: // /dev/null�� 75
return (rw==READ)?0:count; /*
rw_null */ 76
-case 4: // /dev/port�� 77
return rw_port(rw,EIO; 82 // ����ϵͳ���豸������ // 定义系统中设备种数。 83
#define NRDEVS ((sizeof (crw_table))/(sizeof (c
84 // �ַ��豸��д����ָ����� // 字符设备读写函数指针表。 85
static crw_ptr crw_table[]={ 86
NULL,
/* nodev */
-/* ���豸(���豸) */ 87
rw_memory,
-/* /dev/mem etc */ /* /dev/mem��/* /dev/mem etc */ /* /dev/mem等 */ 88
NULL,
/* /dev/fd */
-/* /dev/fd���� */ 89 NULL,
/* /dev/hd */
-/* /dev/hdӲ�� */ 90
rw_ttyx,
/* /dev/ttyx */
-/* /dev/ttyx�����ն� */ 91
rw_tty,
/* /dev/tty */
-/* /dev/tty�ն� */ 92
NULL,
/* /dev/lp */
-/* /dev/lp��ӡ�� */ 93
NULL};
-/* unnamed pipes */ /* δ�����ܵ� /* unnamed pipes */ /* 未命名管道 */ 94 //// �ַ��豸��д���������� //// 字符设备读写操作函数。 // ������rw
--��д���dev -�豸�ţ�buf -��������count -��д�ֽ�����pos -��дָ�롣 // 参数:rw
+-读写命令;dev -设备号;buf -缓冲区;count -读写字节数;pos -读写指针。 // ���أ�ʵ�ʶ�/д�ֽ����� // 返回:实际读/写字节数。 95 int
rw_char(int rw,int dev, char * buf, int count<
98 // ����豸�ų���ϵͳ�豸�����س����롣������豸û�ж�Ӧ�Ķ�/д������Ҳ���س� // 如果设备号超出系统设备数,则返回出错码。如果该设备没有对应的读/写函数,也返回出 // ���롣������ö�Ӧ�豸�Ķ�д����������������ʵ�ʶ�/д���ֽ����� // 错码。否则调用对应设备的读写操作函数,并返回实际读/写的字节数。 99
if (MAJOR(dev)>=
- ����程序12-12 linux/fs/read_write.c 6 7
-#include <sys/stat.h> // �ļ�״̬ͷ�ļ��������ļ����ļ�ϵͳ״̬�ṹstat{}�ͳ����� 8
-#include <errno.h> // �����ͷ�ļ�������ϵͳ�и��ֳ����š� 9
-#include <sys/types.h> // ����ͷ�ļ��������˻�����ϵͳ�������͡� 10 11
-#include <linux/kernel.h> // �ں�ͷ�ļ�������һЩ�ں˳��ú�����ԭ�ζ��塣 12
-#include <linux/sched.h> // ���ȳ���ͷ�ļ�����������ṹtask_struct������0���ݵȡ� 13
-#include <asm/segment.h> // �β���ͷ�ļ����������йضμĴ���������Ƕ��ʽ��ຯ���� 14 // �ַ��豸��д������fs/char_dev.c����95�С� // 字符设备读写函数。fs/char_dev.c,第95行。 15
extern int rw_char(int rw,int dev, char
* buf, int count,
off_t * pos); // ���ܵ�����������fs/pipe.c����13�С� // 读管道操作函数。fs/pipe.c,第13行。 16
extern int read_pipe(struct m_inode * inode, char * buf, int count); // д�ܵ�����������fs/pipe.c����41�С� // 写管道操作函数。fs/pipe.c,第41行。 17
extern int write_pipe(struct m_inode * inode, char * buf, int count); // ���豸������������fs/block_dev.c����47�С� // 块设备读操作函数。fs/block_dev.c,第47行。 18
extern int block_read(int dev, off_t * pos
char * buf, int count); // ���豸д����������fs/block_dev.c����14�С� // 块设备写操作函数。fs/block_dev.c,第14行。 19
extern int block_write(int dev, off_t * pos
char * buf, int count); // ���ļ�����������fs/file_dev.c����17�С� // 读文件操作函数。fs/file_dev.c,第17行。 20
extern int file_read(struct file * filp, // д�ļ�����������fs/file_dev.c����48�С� // 写文件操作函数。fs/file_dev.c,第48行。 22
extern int file_write(struct count); 24 //// �ض�λ�ļ���дָ��ϵͳ���á� //// 重定位文件读写指针系统调用。 // ����fd���ļ������offset���µ��ļ���дָ��ƫ��ֵ��origin��ƫ�Ƶ���ʼλ�ã����� // 参数fd是文件句柄,offset是新的文件读写指针偏移值,origin是偏移的起始位置,可有 // ����ѡ��SEEK_SET��0�����ļ���ʼ������SEEK_CUR��1���ӵ�ǰ��дλ�ã���SEEK_END�� // 三种选择:SEEK_SET(0,从文件开始处)、SEEK_CUR(1,从当前读写位置)、SEEK_END( // 2�����ļ�β������ // 2,从文件尾处)。 25 int
sys_lseek(unsigned int fd, 29 // �����жϺ����ṩ�IJ�����Ч�ԡ�����ļ����ֵ���ڳ��������ļ���NR_OPEN(20)�� // 首先判断函数提供的参数有效性。如果文件句柄值大于程序最多打开文件数NR_OPEN(20), // ���߸þ�����ļ��ṹָ��Ϊ�գ����߶�Ӧ�ļ��ṹ��i�ڵ��ֶ�Ϊ�գ�����ָ���豸�ļ� // 或者该句柄的文件结构指针为空,或者对应文件结构的i节点字段为空,或者指定设备文件 // ָ���Dz��ɶ�λ�ģ��س����벢�˳�������ļ���Ӧ��i�ڵ��ǹܵ��ڵ㣬�س��� // 指针是不可定位的,则返回出错码并退出。如果文件对应的i节点是管道节点,则返回出错 // ���˳�����Ϊ�ܵ�ͷβָ�벻�������ƶ��� // 码退出。因为管道头尾指针不可随意移动! 30 if
(fd >= NR_OPEN || !(file->f_inode->i_pipe)
34
return -ESPIPE; // Ȼ��������õĶ�λ��־���ֱ����¶�λ�ļ���дָ�롣 // 然后根据设置的定位标志,分别重新定位文件读写指针。 35
switch (origin) { // origin = SEEK_SET��Ҫ�����ļ���ʼ����Ϊԭ�������ļ���дָ�롣��ƫ��ֵС���㣬��� // origin = SEEK_SET,要求以文件起始处作为原点设置文件读写指针。若偏移值小于零,则出 // �����ش����롣���������ļ���дָ�����offset�� // 错返回错误码。否则设置文件读写指针等于offset。 36
case 0: 39
break; // origin = SEEK_CUR��Ҫ�����ļ���ǰ��дָ�봦��Ϊԭ���ض�λ��дָ�롣����ļ���ǰָ // origin = SEEK_CUR,要求以文件当前读写指针处作为原点重定位读写指针。如果文件当前指 // �����ƫ��ֵС��0���س������˳��������ڵ�ǰ��дָ���ϼ���ƫ��ֵ�� // 针加上偏移值小于0,则返回出错码退出。否则在当前读写指针上加上偏移值。 40
case 1: 43
break; // origin = SEEK_END��Ҫ�����ļ�ĩβ��Ϊԭ���ض�λ��дָ�롣��ʱ���ļ���С����ƫ��ֵ // origin = SEEK_END,要求以文件末尾作为原点重定位读写指针。此时若文件大小加上偏移值 // С�����س������˳��������ض�λ��дָ��Ϊ�ļ����ȼ���ƫ��ֵ�� // 小于零则返回出错码退出。否则重定位读写指针为文件长度加上偏移值。 44
case 2: 48
break; // ��origin
-������Ч�����س������˳��� // 若origin
+设置无效,返回出错码退出。 49
default: 52
return file->f_pos;
-// ����ض�λ����ļ���дָ��ֵ�� 53 } 54 //// ���ļ�ϵͳ���á� //// 读文件系统调用。 // ����fd���ļ������buf�ǻ�������count�������ֽ����� // 参数fd是文件句柄,buf是缓冲区,count是欲读字节数。 55 int
sys_read(unsigned int fd,char * m_inode * inode; 59 // �������ȶԲ�����Ч�Խ����жϡ�����ļ����ֵ���ڳ��������ļ���NR_OPEN������ // 函数首先对参数有效性进行判断。如果文件句柄值大于程序最多打开文件数NR_OPEN,或者 // ��Ҫ��ȡ���ֽڼ���ֵС��0�����߸þ�����ļ��ṹָ��Ϊ�գ��س����벢�˳����� // 需要读取的字节计数值小于0,或者该句柄的文件结构指针为空,则返回出错码并退出。若 // ���ȡ���ֽ���count����0����0�˳� // 需读取的字节数count等于0,则返回0退出 60
if (fd>=NR_OPEN || count) 63
return 0; // Ȼ����֤������ݵĻ������ڴ����ơ���ȡ�ļ���i�ڵ㡣���ڸ��ݸ�i�ڵ�����ԣ��ֱ� // 然后验证存放数据的缓冲区内存限制。并取文件的i节点。用于根据该i节点的属性,分别 // ������Ӧ�Ķ��������������ǹܵ��ļ��������Ƕ��ܵ��ļ�ģʽ������ж��ܵ����������� // 调用相应的读操作函数。若是管道文件,并且是读管道文件模式,则进行读管道操作,若成 // ���ض�ȡ���ֽ��������س����룬�˳���������ַ����ļ�������ж��ַ��豸�� // 功则返回读取的字节数,否则返回出错码,退出。如果是字符型文件,则进行读字符设备操 // ���������ض�ȡ���ַ���������ǿ��豸�ļ�����ִ�п��豸�������������ض�ȡ���ֽ����� // 作,并返回读取的字符数。如果是块设备文件,则执行块设备读操作,并返回读取的字节数。 64
verify_area(buf,block_read(inode->i_zone[0],&am
style='color:blue'>file->f_pos,buf,count); // �����Ŀ¼�ļ������dz����ļ�����������֤��ȡ�ֽ���count����Ч�Բ����е��������� // 如果是目录文件或者是常规文件,则首先验证读取字节数count的有效性并进行调整(若读 // ȡ�ֽ��������ļ���ǰ��дָ��ֵ�����ļ����ȣ����������ö�ȡ�ֽ���Ϊ
-�ļ�����-��ǰ // 取字节数加上文件当前读写指针值大于文件长度,则重新设置读取字节数为
+文件长度-当前 // ��дָ��ֵ������ȡ������0����0�˳�����Ȼ��ִ���ļ������������ض�ȡ���ֽ��� // 读写指针值,若读取数等于0,则返回0退出),然后执行文件读操作,返回读取的字节数 // ���˳��� // 并退出。 72
if (S_ISDIR(inode->i_mode) || count); 78
} // ִ�е����˵���������ж��ļ������ԡ����ӡ�ڵ��ļ����ԣ������س������˳��� // 执行到这里,说明我们无法判断文件的属性。则打印节点文件属性,并返回出错码退出。 79
printk("(Read)inode->i_mode=%06o\n\r",inode->i_mode); 82 //// д�ļ�ϵͳ���á� //// 写文件系统调用。 // ����fd���ļ������buf���û���������count����д�ֽ����� // 参数fd是文件句柄,buf是用户缓冲区,count是欲写字节数。 83 int
sys_write(unsigned int fd,char * m_inode * inode; 87
// ͬ���أ����������жϺ�����������Ч�ԡ���������ļ����ֵ���ڳ��������ļ��� // 同样地,我们首先判断函数参数的有效性。如果进程文件句柄值大于程序最多打开文件数 // NR_OPEN��������Ҫд����ֽڼ���С��0�����߸þ�����ļ��ṹָ��Ϊ�գ��س��� // NR_OPEN,或者需要写入的字节计数小于0,或者该句柄的文件结构指针为空,则返回出错 // �벢�˳���������ȡ���ֽ���count����0����0�˳� // 码并退出。如果需读取的字节数count等于0,则返回0退出 88
if (fd>=NR_OPEN || count) 91
return 0; // Ȼ����֤������ݵĻ������ڴ����ơ���ȡ�ļ���i�ڵ㡣���ڸ��ݸ�i�ڵ�����ԣ��ֱ� // 然后验证存放数据的缓冲区内存限制。并取文件的i节点。用于根据该i节点的属性,分别 // ������Ӧ�Ķ��������������ǹܵ��ļ���������д�ܵ��ļ�ģʽ�������д�ܵ����������� // 调用相应的读操作函数。若是管道文件,并且是写管道文件模式,则进行写管道操作,若成 // ����д����ֽ��������س������˳���������ַ��豸�ļ��������д�ַ��豸�� // 功则返回写入的字节数,否则返回出错码退出。如果是字符设备文件,则进行写字符设备操 // ��������д����ַ����˳�������ǿ��豸�ļ�������п��豸д������������д����ֽ� // 作,返回写入的字符数退出。如果是块设备文件,则进行块设备写操作,并返回写入的字节 // ���˳������dz����ļ�����ִ���ļ�д������������д����ֽ������˳��� // 数退出。若是常规文件,则执行文件写操作,并返回写入的字节数,退出。 92
inode=file->f_inode; // ִ�е����˵���������ж��ļ������ԡ����ӡ�ڵ��ļ����ԣ������س������˳��� // 执行到这里,说明我们无法判断文件的属性。则打印节点文件属性,并返回出错码退出。 101
-
6 7
-#include <string.h> // �ַ���ͷ�ļ�����Ҫ������һЩ�й��ַ���������Ƕ�뺯���� 8
-#include <errno.h> // �����ͷ�ļ�������ϵͳ�и��ֳ����š� 9
-#include <fcntl.h> // �ļ�����ͷ�ļ��������ļ������������������Ƴ������Ŷ��塣 10
-#include <sys/types.h> // ����ͷ�ļ������������ϵͳ���ļ�ϵͳͳ����Ϣ�ṹ�����͡� 11
-#include <utime.h> // �û�ʱ��ͷ�ļ���������ʺ���ʱ��ṹ�Լ�utime()ԭ�͡� 12
-#include <sys/stat.h> // �ļ�״̬ͷ�ļ��������ļ�״̬�ṹstat{}�ͷ��ų����ȡ� 13 14
-#include <linux/sched.h> // ���ȳ���ͷ�ļ�����������ṹtask_struct������0���ݵȡ� 15
-#include <linux/tty.h> // ttyͷ�ļ����������й�tty_io������ͨ�ŷ���IJ����������� 16
-#include <linux/kernel.h> // �ں�ͷ�ļ�������һЩ�ں˳��ú�����ԭ�ζ��塣 17 18
-#include <asm/segment.h> // �β���ͷ�ļ����������йضμĴ���������Ƕ��ʽ��ຯ���� 19 //// ȡ�ļ�ϵͳ��Ϣ�� //// 取文件系统信息。 // ����dev�Ǻ����Ѱ�װ�ļ�ϵͳ���豸�š�ubuf��һ��ustat�ṹ������ָ�룬���ڴ�� // 参数dev是含有已安装文件系统的设备号。ubuf是一个ustat结构缓冲区指针,用于存放 // ϵͳ���ص��ļ�ϵͳ��Ϣ����ϵͳ�������ڷ����Ѱ�װ��mounted���ļ�ϵͳ��ͳ����Ϣ�� // 系统返回的文件系统信息。该系统调用用于返回已安装(mounted)文件系统的统计信息。 // �ɹ�ʱ����0������ubufָ���ustate�ṹ�������ļ�ϵͳ�ܿ��п����Ϳ���i�ڵ����� // 成功时返回0,并且ubuf指向的ustate结构被添入文件系统总空闲块数和空闲i节点数。 // ustat�ṹ������include/sys/types.h�С� // ustat结构定义在include/sys/types.h中。 20 int
sys_ustat(int dev, struct ustat * ubuf) 22
return -ENOSYS;
-// �����룺���ܻ�δʵ�֡� 23 } 24 //// �����ļ����ʺ���ʱ�䡣 //// 设置文件访问和修改时间。 // ����filename���ļ�����times�Ƿ��ʺ���ʱ��ṹָ�롣 // 参数filename是文件名,times是访问和修改时间结构指针。 // ���timesָ�벻ΪNULL����ȡutimbuf�ṹ�е�ʱ����Ϣ�������ļ��ķ��ʺ���ʱ�䡣 // 如果times指针不为NULL,则取utimbuf结构中的时间信息来设置文件的访问和修改时间。 // ���timesָ����NULL����ȡϵͳ��ǰʱ��������ָ���ļ��ķ��ʺ���ʱ���� // 如果times指针是NULL,则取系统当前时间来设置指定文件的访问和修改时间域。 25 int
sys_utime(char * filename, struct 29 // �ļ���ʱ����Ϣ��������i�ڵ��ӡ�����������ȸ����ļ���ȡ�ö�Ӧi�ڵ㡣���û���� // 文件的时间信息保存在其i节点钟。因此我们首先根据文件名取得对应i节点。如果没有找 // �����س����롣����ṩ�ķ��ʺ���ʱ��ṹָ��times��ΪNULL����ӽṹ�ж�ȡ // 到,则返回出错码。如果提供的访问和修改时间结构指针times不为NULL,则从结构中读取 // �û����õ�ʱ��ֵ���������ϵͳ��ǰʱ���������ļ��ķ��ʺ���ʱ�䡣 // 用户设置的时间值。否则就用系统当前时间来设置文件的访问和修改时间。 30
if (!(inode=namei(filename))) 36
actime = modtime = CURRENT_TIME; // Ȼ����i�ڵ��еķ���ʱ���ֶκ���ʱ���ֶΡ�������i�ڵ����ı�־���Żظ�i�� // 然后修改i节点中的访问时间字段和修改时间字段。再设置i节点已修改标志,放回该i节 // �㣬������0�� // 点,并返回0。 37
inode->i_atime = actime; /* * XXX ���Ǹ�����ʵ�û�id��ruid��������Ч�û�id��euid����BSDϵͳʹ���� * XXX 我们该用真实用户id(ruid)还是有效用户id(euid)?BSD系统使用了 * ��ʵ�û�id����ʹ�õ��ÿ��Թ�setuid����ʹ�á� * 真实用户id,以使该调用可以供setuid程序使用。 * ��ע��POSIX������ʹ����ʵ�û�ID���� * (注:POSIX标准建议使用真实用户ID)。 * ��ע1��Ӣ��ע�Ϳ�ʼ�� 'XXX' ��ʾ��Ҫ��ʾ���� * (注1:英文注释开始的 'XXX' 表示重要提示)。 */ //// ����ļ��ķ���Ȩ�ޡ� //// 检查文件的访问权限。 // ����filename���ļ�����mode�Ǽ��ķ������ԣ�����3����Ч����λ��ɣ�R_OK(ֵ4)�� // 参数filename是文件名,mode是检查的访问属性,它有3个有效比特位组成:R_OK(值4)、 // W_OK(2)��X_OK(1) ��F_OK(0) ��ɣ��ֱ��ʾ����ļ��Ƿ�ɶ�����д����ִ�к��ļ��� // W_OK(2)、X_OK(1) 和F_OK(0) 组成,分别表示检测文件是否可读、可写、可执行和文件是 // ����ڡ�������������Ļ�����0�����س����롣 // 否存在。如果访问允许的话,则返回0,否则返回出错码。 48 int
sys_access(const char * filename,int
@@ -2049,19 +2049,19 @@ int res, i_mode; 52 // �ļ��ķ���Ȩ����ϢҲͬ���������ļ���i�ڵ�ṹ�У��������Ҫ��ȡ�ö�Ӧ�ļ�����i // 文件的访问权限信息也同样保存在文件的i节点结构中,因此我们要先取得对应文件名的i // �ڵ㡣���ķ�������mode�ɵ�3λ��ɣ������Ҫ���ϰ˽���0007��������и߱���λ�� // 节点。检测的访问属性mode由低3位组成,因此需要与上八进制0007来清除所有高比特位。 // ����ļ�����Ӧ��i�ڵ㲻���ڣ���û������Ȩ�����롣��i�ڵ���ڣ���ȡi�ڵ� // 如果文件名对应的i节点不存在,则返回没有许可权限出错码。若i节点存在,则取i节点 // ���ļ������룬���Żظ�i�ڵ㡣���⣬57������䡰iput(inode);��������61��֮�� // 钟文件属性码,并放回该i节点。另外,57行上语句“iput(inode);”最后放在61行之后。 53
mode &= 0007; 55
return -EACCES;
-// �����룺����Ȩ�ޡ� 56
i_mode = res = inode->i_mode & 0777; 57
iput(inode); // �����ǰ�����û��Ǹ��ļ�����������ȡ�ļ��������ԡ����������ǰ�����û�����ļ��� // 如果当前进程用户是该文件的宿主,则取文件宿主属性。否则如果当前进程用户与该文件宿 // ��ͬ��һ�飬��ȡ�ļ������ԡ�����ʱres���3�����������˷��ʸ��ļ����������ԡ� // 主同属一组,则取文件组属性。否则,此时res最低3比特是其他人访问该文件的许可属性。 // [[?? ����Ӧ // [[?? 这里应res >>3 ??] 58
@@ -2100,11 +2100,11 @@ inode->i_gid) 61
res >>= 6; // ��ʱres�����3�����Ǹ��ݵ�ǰ�����û����ļ��Ĺ�ϵѡ������ķ�������λ���������� // 此时res的最低3比特是根据当前进程用户与文件的关系选择出来的访问属性位。现在我们 // ���ж���3���ء�����ļ����Ծ��в�������ѯ������λmode����������ɣ�����0 // 来判断这3比特。如果文件属性具有参数所查询的属性位mode,则访问许可,返回0 62
if ((res & 0007 & mode) == mode)
-* XXX ��������������IJ��ԣ���Ϊ����ʵ������Ҫ������Ч�û�ID��
-* ��ʵ�û�ID����ʱ�أ���Ȼ��ŵ���suser()�������������ȷʵҪ����
-* suser()����������Ҫ���ű����á�
*/ // �����ǰ�û�IDΪ0�������û�������������ִ��λ��0�����ļ����Ա��κ���ִ�С��� // 如果当前用户ID为0(超级用户)并且屏蔽码执行位是0或者文件可以被任何人执行、搜 // ������0�����س����롣 // 索,则返回0。否则返回出错码。 70
if ((!current->uid) && 73
return -EACCES;
-// �����룺����Ȩ�ޡ� 74 } 75 //// �ı䵱ǰ����Ŀ¼ϵͳ���á� //// 改变当前工作目录系统调用。 // ����filename��Ŀ¼���� // 参数filename是目录名。 // �����ɹ���0�����س����롣 // 操作成功则返回0,否则返回出错码。 76 int
sys_chdir(const char * filename) 79 // �ı䵱ǰ����Ŀ¼����Ҫ��ѽ�������ṹ�ĵ�ǰ����Ŀ¼�ֶ�ָ�����Ŀ¼����i�ڵ㡣 // 改变当前工作目录就是要求把进程任务结构的当前工作目录字段指向给定目录名的i节点。 // �����������ȡĿ¼����i�ڵ㡣���Ŀ¼����Ӧ��i�ڵ㲻���ڣ��س����롣����� // 因此我们首先取目录名的i节点。如果目录名对应的i节点不存在,则返回出错码。如果该 // i�ڵ㲻��һ��Ŀ¼i�ڵ㣬��Żظ�i�ڵ㣬�����س����롣 // i节点不是一个目录i节点,则放回该i节点,并返回出错码。 80
if (!(inode = namei(filename))) 81
return -ENOENT;
-// �����룺�ļ���Ŀ¼�����ڡ� 82
if (!S_ISDIR(inode->i_mode)) { 84
return -ENOTDIR;
-// �����룺����Ŀ¼���� 85
} // Ȼ���ͷŽ���ԭ����Ŀ¼i�ڵ㣬��ʹ��ָ�������õĹ���Ŀ¼i�ڵ㡣����0�� // 然后释放进程原工作目录i节点,并使其指向新设置的工作目录i节点。返回0。 86
iput(current->pwd); 90 //// �ı��Ŀ¼ϵͳ���á� //// 改变根目录系统调用。 // ��ָ����Ŀ¼�����ó�Ϊ��ǰ���̵ĸ�Ŀ¼'/'�� // 把指定的目录名设置成为当前进程的根目录'/'。 // ��������ɹ���0�����س����롣 // 如果操作成功则返回0,否则返回出错码。 91 int
sys_chroot(const char * filename) 94 // �õ������ڸı䵱ǰ��������ṹ�еĸ�Ŀ¼�ֶ�root������ָ���������Ŀ¼����i�ڵ㡣 // 该调用用于改变当前进程任务结构中的根目录字段root,让其指向参数给定目录名的i节点。 // ���Ŀ¼����Ӧ��i�ڵ㲻���ڣ��س����롣�����i�ڵ㲻��Ŀ¼i�ڵ㣬��Żظ� // 如果目录名对应的i节点不存在,则返回出错码。如果该i节点不是目录i节点,则放回该 // i�ڵ㣬Ҳ���س����롣 // i节点,也返回出错码。 95
if (!(inode=namei(filename))) 100 } // Ȼ���ͷŵ�ǰ���̵ĸ�Ŀ¼i�ڵ㣬����������Ϊָ��Ŀ¼����i�ڵ㣬����0�� // 然后释放当前进程的根目录i节点,并重新设置为指定目录名的i节点,返回0。 101 } 105 //// ���ļ�����ϵͳ���á� //// 修改文件属性系统调用。 // ����filename���ļ�����mode���µ��ļ����ԡ� // 参数filename是文件名,mode是新的文件属性。 // �������ɹ���0�����س����롣 // 若操作成功则返回0,否则返回出错码。 106 int sys_chmod(const char *
@@ -2317,16 +2317,16 @@ style='color:blue'>m_inode * inode; 109 // �õ���Ϊָ���ļ������µķ�������mode���ļ��ķ����������ļ�����Ӧ��i�ڵ��У���� // 该调用为指定文件设置新的访问属性mode。文件的访问属性在文件名对应的i节点中,因此 // ��������ȡ�ļ�����Ӧ��i�ڵ㡣���i�ڵ㲻���ڣ��س����루�ļ���Ŀ¼�����ڣ��� // 我们首先取文件名对应的i节点。如果i节点不存在,则返回出错码(文件或目录不存在)。 // �����ǰ���̵���Ч�û�id���ļ�i�ڵ���û�id��ͬ������Ҳ���dz����û�����Żظ� // 如果当前进程的有效用户id与文件i节点的用户id不同,并且也不是超级用户,则放回该 // �ļ�i�ڵ㣬���س����루û�з���Ȩ�ޣ��� // 文件i节点,返回出错码(没有访问权限)。 110 if (!(inode=EACCES; 115 } // ������������ø�i�ڵ���ļ����ԣ����ø�i�ڵ����ı�־���Żظ�i�ڵ㣬����0�� // 否则就重新设置该i节点的文件属性,并置该i节点已修改标志。放回该i节点,返回0。 116 inode->i_mode =
@@ -2377,14 +2377,14 @@ lang=EN-US> } 121 //// ���ļ�����ϵͳ���á� //// 修改文件宿主系统调用。 // ����filename���ļ�����uid���û���ʶ��(�û�ID)��gid����ID�� // 参数filename是文件名,uid是用户标识符(用户ID),gid是组ID。 // �������ɹ���0�����س����롣 // 若操作成功则返回0,否则返回出错码。 122 int sys_chown(const char *
@@ -2400,13 +2400,13 @@ style='color:blue'>m_inode * inode; 125 // �õ������������ļ�i�ڵ��е��û�����ID���������Ҫȡ�ø����ļ�����i�ڵ㡣����� // 该调用用于设置文件i节点中的用户和组ID,因此首先要取得给定文件名的i节点。如果文 // ������i�ڵ㲻���ڣ��س����루�ļ���Ŀ¼�����ڣ��������ǰ���̲��dz����û��� // 件名的i节点不存在,则返回出错码(文件或目录不存在)。如果当前进程不是超级用户, // ��Żظ�i�ڵ㣬�����س����루û�з���Ȩ�ޣ��� // 则放回该i节点,并返回出错码(没有访问权限)。 126 if (!(inode=EACCES; 131 } // �������Ǿ��ò����ṩ��ֵ�������ļ�i�ڵ���û�ID����ID������i�ڵ��Ѿ��ı�־�� // 否则我们就用参数提供的值来设置文件i节点的用户ID和组ID,并置i节点已经修改标志, // �Żظ�i�ڵ㣬����0�� // 放回该i节点,返回0。 132
@@ -2462,16 +2462,16 @@ lang=EN-US> } 138 //// ����ַ��豸���͡� //// 检查字符设备类型。 // �ú��������������ļ���ϵͳ����sys_open()�����ڼ�������ļ���tty�ն��ַ��� // 该函数仅用于下面文件打开系统调用sys_open(),用于检查若打开的文件是tty终端字符设 // ��ʱ����Ҫ�Ե�ǰ���̵����úͶ�tty�������á� // 备时,需要对当前进程的设置和对tty表的设置。 // ����0�����ɹ�������-1��ʾʧ�ܣ���Ӧ�ַ��豸���ܴ� // 返回0检测处理成功,返回-1表示失败,对应字符设备不能打开。 139 static int check_char_dev(struct
@@ -2487,36 +2487,36 @@ style='color:blue'>tty_struct *tty; 142 int min;
//
-���豸�š� 143 // ֻ�������豸����4��/dev/ttyxx�ļ�����5��/dev/tty�ļ����������/dev/tty�����豸 // 只处理主设备号是4(/dev/ttyxx文件)或5(/dev/tty文件)的情况。/dev/tty的子设备 // ����0�����һ�������п����նˣ������ǽ��̿����ն��豸��ͬ��������/dev/tty�豸�� // 号是0。如果一个进程有控制终端,则它是进程控制终端设备的同义名。即/dev/tty设备是 // һ�������豸������Ӧ������ʵ��ʹ�õ�/dev/ttyxx�豸֮һ������һ��������˵�������� // 一个虚拟设备,它对应到进程实际使用的/dev/ttyxx设备之一。对于一个进程来说,若其有 // �����նˣ���ô��������ṹ�е�tty�ֶν���4���豸��ijһ�����豸�š� // 控制终端,那么它的任务结构中的tty字段将是4号设备的某一个子设备号。 // ����������ļ��� /dev/tty����MAJOR(dev) = 5������ô������min = ��������ṹ // 如果打开操作的文件是 /dev/tty(即MAJOR(dev) = 5),那么我们令min = 进程任务结构 // �е�tty�ֶΣ���ȡ4���豸�����豸�š������������ij��4���豸����ֱ��ȡ���� // 中的tty字段,即取4号设备的子设备号。否则如果打开的是某个4号设备,则直接取其子 // �豸�š�����õ��� 4���豸���豸��С��0����ô˵������û�п����նˣ������豸�Ŵ� // 设备号。如果得到的 4号设备子设备号小于0,那么说明进程没有控制终端,或者设备号错 // ����
--1����ʾ���ڽ���û�п����նˣ����߲��ܴ�����豸�� // 误,则返回
+-1,表示由于进程没有控制终端,或者不能打开这个设备。 144 if ( // ��α�ն��豸�ļ�ֻ�ܱ����̶�ռʹ�á�������豸�ű�����һ����α�նˣ����Ҹô��ļ� // 主伪终端设备文件只能被进程独占使用。如果子设备号表明是一个主伪终端,并且该打开文件 // i �ڵ����ü������� 1����˵�����豸�ѱ���������ʹ�á���˲����ٴ��ַ��豸�ļ��� // i 节点引用计数大于 1,则说明该设备已被其他进程使用。因此不能再打开该字符设备文件, // ���Ƿ���
--1������������tty�ṹָ��ttyָ��tty���ж�Ӧ�ṹ������ļ������� // 于是返回
+-1。否则,我们让tty结构指针tty指向tty表中对应结构项。若打开文件操作标 // ־flag�в�����������ն˱�־O_NOCTTY�����ҽ����ǽ��������죬���ҵ�ǰ����û�п��� // 志flag中不含无需控制终端标志O_NOCTTY,并且进程是进程组首领,并且当前进程没有控制 // �նˣ�����tty�ṹ��session�ֶ�Ϊ0����ʾ���ն˻������κν�����Ŀ����նˣ�����ô // 终端,并且tty结构中session字端为0(表示该终端还不是任何进程组的控制终端),那么 // ������Ϊ������������ն��豸 min Ϊ������նˡ��������ý�������ṹ�ն��豸���ֶ� // 就允许为进程设置这个终端设备 min 为其控制终端。于是设置进程任务结构终端设备号字段 // ttyֵ����min���������ö�Ӧtty�ṹ�ĻỰ��session�ͽ������pgrp�ֱ���ڽ��̵Ļ� // tty值等于min,并且设置对应tty结构的会话号session和进程组号pgrp分别等于进程的会 // ���źͽ�����š� // 话号和进程组号。 151
@@ -2616,19 +2616,19 @@ tty->pgrp = current->pgrp;
lang=EN-US>
} // ������ļ�������־flag�к���O_NONBLOCK������������־����������Ҫ�Ը��ַ��ն� // 如果打开文件操作标志flag中含有O_NONBLOCK(非阻塞)标志,则我们需要对该字符终端 // �豸����������ã�����Ϊ�����������Ҫ��ȡ�������ַ���Ϊ0�����ó�ʱ��ʱֵΪ0�� // 设备进行相关设置,设置为满足读操作需要读取的最少字符数为0,设置超时定时值为0, // �����ն��豸���óɷǹ淶ģʽ����������ʽֻ�ܹ����ڷǹ淶ģʽ���ڴ�ģʽ�µ� // 并把终端设备设置成非规范模式。非阻塞方式只能工作于非规范模式。在此模式下当VMIN // ��VTIME������Ϊ0ʱ�������������ж���֧�����̾Ͷ�ȡ�����ַ��������̷��ء��μ� // 和VTIME均设置为0时,辅助队列中有多少支付进程就读取多少字符,并立刻返回。参见 // include/termios.h�ļ����˵���� // include/termios.h文件后的说明。 162
@@ -2667,30 +2667,30 @@ lang=EN-US> } 170 //// �������ļ�ϵͳ���á� //// 打开(或创建)文件系统调用。 // ����filename���ļ�����flag�Ǵ��ļ���־������ȡֵ��O_RDONLY��ֻ������ // 参数filename是文件名,flag是打开文件标志,它可取值:O_RDONLY(只读)、O_WRONLY // ��ֻд����O_RDWR����д�����Լ�O_CREAT����������O_EXCL���������ļ����벻���ڣ��� // (只写)或O_RDWR(读写),以及O_CREAT(创建)、O_EXCL(被创建文件必须不存在)、 // O_APPEND�����ļ�β�������ݣ�������һЩ��־����ϣ���������ô�����һ�����ļ����� // O_APPEND(在文件尾添加数据)等其他一些标志的组合,如果本调用创建了一个新文件,则 // mode������ָ���ļ����������ԡ���Щ������S_IRWXU���ļ��������ж���д��ִ��Ȩ�ޣ��� // mode就用于指定文件的许可属性。这些属性有S_IRWXU(文件宿主具有读、写和执行权限)、 // S_IRUSR���û����ж��ļ�Ȩ�ޣ���S_IRWXG�����Ա���ж���д��ִ��Ȩ�ޣ��ȵȡ������� // S_IRUSR(用户具有读文件权限)、S_IRWXG(组成员具有读、写和执行权限)等等。对于新 // �������ļ�����Щ����ֻӦ���ڽ������ļ��ķ��ʣ�������ֻ���ļ��Ĵ���Ҳ������һ // 创建的文件,这些属性只应用于将来对文件的访问,创建了只读文件的打开调用也将返回一 // ���ɶ�д���ļ������������ò����ɹ������ļ����(�ļ�������)�����س����롣 // 个可读写的文件句柄。如果调用操作成功,则返回文件句柄(文件描述符),否则返回出错码。 // �μ�sys/stat.h��fcntl.h�� // 参见sys/stat.h、fcntl.h。 171 int sys_open(const char *
@@ -2713,12 +2713,12 @@ lang=EN-US> int i,fd; 176 // ���ȶԲ������д��������û����õ��ļ�ģʽ�ͽ���ģʽ���������룬�������ɵ��ļ�ģʽ�� // 首先对参数进行处理。将用户设置的文件模式和进程模式屏蔽码相与,产生许可的文件模式。 // Ϊ��Ϊ���ļ�����һ���ļ��������Ҫ�������̽ṹ���ļ��ṹָ�����飬�Բ���һ���� // 为了为打开文件建立一个文件句柄,需要搜索进程结构中文件结构指针数组,以查找一个空 // ����������������fd���Ǿ��ֵ�����Ѿ�û�п�����س����루������Ч���� // 闲项。空闲项的索引号fd即是句柄值。若已经没有空闲项,则返回出错码(参数无效)。 177 mode &= 0777
@@ -2731,7 +2731,7 @@ style='color:blue'>NR_OPEN ; fd++) 179
if (!current->filp[fd])
-// �ҵ������ 180
@@ -2745,35 +2745,35 @@ style='color:blue'>NR_OPEN) // Ȼ���������õ�ǰ���̵�ִ��ʱ�ر��ļ������close_on_exec��λͼ����λ��Ӧ�ı���λ�� // 然后我们设置当前进程的执行时关闭文件句柄(close_on_exec)位图,复位对应的比特位。 // close_on_exec ��һ�����������ļ������λͼ��־��ÿ������λ����һ�����ŵ��ļ��� // close_on_exec 是一个进程所有文件句柄的位图标志。每个比特位代表一个打开着的文件描 // ����������ȷ���ڵ���ϵͳ���� execve()ʱ��Ҫ�رյ��ļ������������ʹ�� fork()���� // 述符,用于确定在调用系统调用 execve()时需要关闭的文件句柄。当程序使用 fork()函数 // ������һ���ӽ���ʱ��ͨ�����ڸ��ӽ����е���execve()��������ִ����һ���³���ʱ // 创建了一个子进程时,通常会在该子进程中调用execve()函数加载执行另一个新程序。此时 // �ӽ����п�ʼִ���³�����һ���ļ������close_on_exec�еĶ�Ӧ����λ����λ����ô // 子进程中开始执行新程序。若一个文件句柄在close_on_exec中的对应比特位被置位,那么 // ��ִ��execve()ʱ�ö�Ӧ�ļ���������رգ�������ļ������ʼ�մ��ڴ�״̬������ // 在执行execve()时该对应文件句柄将被关闭,否则该文件句柄将始终处于打开状态。当打开 // һ���ļ�ʱ��Ĭ��������ļ�������ӽ�����Ҳ���ڴ�״̬���������Ҫ��λ��Ӧ����λ�� // 一个文件时,默认情况下文件句柄在子进程中也处于打开状态。因此这里要复位对应比特位。 // Ȼ��Ϊ���ļ����ļ�����Ѱ��һ�����нṹ�������fָ���ļ������鿪ʼ���������� // 然后为打开文件在文件表中寻找一个空闲结构项。我们令f指向文件表数组开始处。搜索空 // ���ļ��ṹ����ü���Ϊ0��������Ѿ�û�п����ļ����ṹ��س����롣���⣬ // 闲文件结构项(引用计数为0的项),若已经没有空闲文件表结构项,则返回出错码。另外, // ��184���ϵ�ָ�븳ֵ
-"0+file_table " ��ͬ�� "file_table"
-�� "&file_table[0]"�� // 第184行上的指针赋值
+"0+file_table " 等同于 "file_table"
+和 "&file_table[0]"。 // ��������д���ܸ�������һЩ�� // 不过这样写可能更能明了一些。 183 NR_FILE) // ��ʱ�����ý��̶�Ӧ�ļ����fd���ļ��ṹָ��ָ�����������ļ��ṹ�������ļ����ü��� // 此时我们让进程对应文件句柄fd的文件结构指针指向搜索到的文件结构,并令文件引用计数 // ����1��Ȼ����ú���open_namei()ִ�д�����������ֵС��0����˵�������������ͷ� // 递增1。然后调用函数open_namei()执行打开操作,若返回值小于0,则说明出错,于是释放 // �����뵽���ļ��ṹ�����س�����i�����ļ������ɹ�����inode���Ѵ��ļ���i�ڵ� // 刚申请到的文件结构,返回出错码i。若文件打开操作成功,则inode是已打开文件的i节点 // ָ�롣 // 指针。 189 ( 194 } // �����Ѵ��ļ�i�ڵ�������ֶΣ����ǿ���֪���ļ������͡����ڲ�ͬ���͵��ļ������� // 根据已打开文件i节点的属性字段,我们可以知道文件的类型。对于不同类型的文件,我们 // ��Ҫ��һЩ�ر����� ��������ַ��豸�ļ�����ô���Ǿ�Ҫ���� // 需要作一些特别处理。 如果打开的是字符设备文件,那么我们就要调用check_char_dev() // ��������鵱ǰ�����Ƿ��ܴ�����ַ��豸�ļ��������������������0������ô�� // 函数来检查当前进程是否能打开这个字符设备文件。如果允许(函数返回0),那么在 // check_char_dev()�л���ݾ����ļ���־Ϊ�������ÿ����նˡ�
-����������� // check_char_dev()中会根据具体文件打开标志为进程设置控制终端。
+如果不允许打开 // ʹ�ø��ַ��豸�ļ�����ô����ֻ���ͷ�����������ļ���;����Դ�����س����롣 // 使用该字符设备文件,那么我们只能释放上面申请的文件项和句柄资源,返回出错码。 195 /* ttys are somewhat special (ttyxx major==4, tty major==5)
*/ /* ttys��Щ���⣨ttyxx�����豸��==4��tty�����豸��==5��*/ /* ttys有些特殊(ttyxx的主设备号==4,tty的主设备号==5)*/ 196 if ( 201 return
-EAGAIN;
-// �����ţ���Դ��ʱ�����á� 202
} // ������ǿ��豸�ļ���������Ƭ�Ƿ��������������������Ҫ�ø��ٻ������и��豸 // 如果打开的是块设备文件,则检查盘片是否更换过。若更换过则需要让高速缓冲区中该设备 // �����л����ʧЧ�� // 的所有缓冲块失效。 203 /* Likewise with block-devices: check for floppy_change */ /* ͬ�����ڿ��豸�ļ�����Ҫ�����Ƭ�Ƿ��� /* 同样对于块设备文件:需要检查盘片是否被更换 */ 204S_ISBLK(inode->i_mode)) // �������dz�ʼ�����ļ����ļ��ṹ�������ļ��ṹ���Ժͱ�־���þ�����ü���Ϊ1���� // 现在我们初始化打开文件的文件结构。设置文件结构属性和标志,置句柄引用计数为1,并 // ����i�ڵ��ֶ�Ϊ���ļ���i�ڵ㣬��ʼ���ļ���дָ��Ϊ0������ļ�����š� // 设置i节点字段为打开文件的i节点,初始化文件读写指针为0。最后返回文件句柄号。 206 f->f_mode =
@@ -2940,12 +2940,12 @@ lang=EN-US> } 213 //// �����ļ�ϵͳ���á� //// 创建文件系统调用。 // ����pathname��·������mode�������sys_open()������ͬ�� // 参数pathname是路径名,mode与上面的sys_open()函数相同。 // �ɹ����ļ���������س����롣 // 成功则返回文件句柄,否则返回出错码。 214 int sys_creat(const char *
@@ -2965,11 +2965,11 @@ lang=EN-US> } 218 // �ر��ļ�ϵͳ���á� // 关闭文件系统调用。 // ����fd���ļ������ // 参数fd是文件句柄。 // �ɹ���0�����س����롣 // 成功则返回0,否则返回出错码。 219 int sys_close(unsigned int
@@ -2985,13 +2985,13 @@ style='color:blue'>file * filp; 222 // ���ȼ�������Ч�ԡ����������ļ����ֵ���ڳ���ͬʱ�ܴ��ļ���NR_OPEN���� // 首先检查参数有效性。若给出的文件句柄值大于程序同时能打开的文件数NR_OPEN,则返回 // �����루������Ч����Ȼ��λ���̵�ִ��ʱ�ر��ļ����λͼ��Ӧλ�������ļ������Ӧ // 出错码(参数无效)。然后复位进程的执行时关闭文件句柄位图对应位。若该文件句柄对应 // ���ļ��ṹָ����NULL���س����롣 // 的文件结构指针是NULL,则返回出错码。 223 if (fd >= current->filp[fd])) // �����ø��ļ�������ļ��ṹָ��ΪNULL�����ڹر��ļ�֮ǰ����Ӧ�ļ��ṹ�еľ������ // 现在置该文件句柄的文件结构指针为NULL。若在关闭文件之前,对应文件结构中的句柄引用 // �����Ѿ�Ϊ0����˵���ں˳�����ͣ��������Ӧ�ļ��ṹ�����ü�����1����ʱ������� // 计数已经为0,则说明内核出错,停机。否则将对应文件结构的引用计数减1。此时如果它还 // ��Ϊ0����˵����������������ʹ�ø��ļ������Ƿ���0���ɹ�����������ü����ѵ���0�� // 不为0,则说明有其他进程正在使用该文件,于是返回0(成功)。如果引用计数已等于0, // ˵�����ļ��Ѿ�û�н������ã����ļ��ṹ�ѱ�Ϊ���С����ͷŸ��ļ�i�ڵ㣬����0�� // 说明该文件已经没有进程引用,该文件结构已变为空闲。则释放该文件i节点,返回0。 228
-
/* * #!��ʼ�Ľű�����ļ����벿������tytsoʵ�ֵġ� * #!开始的脚本程序的检测代码部分是由tytso实现的。 */ /* * ����ʱ����ʵ����1991.12.1 - ֻ�轫ִ���ļ�ͷ�������ڴ�����뽫���� * 需求时加载实现于1991.12.1 - 只需将执行文件头部读进内存而无须将整个 * ִ���ļ������ؽ��ڴ档ִ���ļ���i�ڵ㱻���ڵ�ǰ���̵Ŀ�ִ���ֶ��� * 执行文件都加载进内存。执行文件的i节点被放在当前进程的可执行字段中 * "current->executable"��ҳ�쳣�����ִ���ļ���ʵ�ʼ��ز�������������� * "current->executable",页异常会进行执行文件的实际加载操作。这很完美。 * * �ҿ�����һ���Ժ���˵��linux�������ģ�ֻ���˲���2Сʱ�Ĺ���ʱ��� * 我可以再一次自豪地说,linux经得起修改:只用了不到2小时的工作时间就 * ��ȫʵ����������ش����� * 完全实现了需求加载处理。 */ 19 20
-#include <signal.h> // �ź�ͷ�ļ��������źŷ��ų������źŽṹ���źŲ�������ԭ�͡� 21
-#include <errno.h> // �����ͷ�ļ�������ϵͳ�и��ֳ����š� 22
-#include <string.h> // �ַ���ͷ�ļ�����Ҫ������һЩ�й��ַ���������Ƕ�뺯���� 23
-#include <sys/stat.h> // �ļ�״̬ͷ�ļ��������ļ�״̬�ṹstat{}�ͷ��ų����ȡ� 24
-#include <a.out.h> // a.outͷ�ļ���������a.outִ���ļ���ʽ��һЩ�ꡣ 25 26
-#include <linux/fs.h> // �ļ�ϵͳͷ�ļ��������ļ����ṹ��file��m_inode���ȡ� 27
-#include <linux/sched.h> // ���ȳ���ͷ�ļ�������������ṹtask_struct������0���ݵȡ� 28
-#include <linux/kernel.h> // �ں�ͷ�ļ�������һЩ�ں˳��ú�����ԭ�ζ��塣 29
-#include <linux/mm.h> // �ڴ����ͷ�ļ�������ҳ���С�����һЩҳ���ͷź���ԭ�͡� 30
-#include <asm/segment.h> // �β���ͷ�ļ����������йضμĴ���������Ƕ��ʽ��ຯ���� 31 32
extern int sys_exit(int exit_code);
-// �˳�����ϵͳ���á� 33
extern int sys_close(int fd);
-// �ر��ļ�ϵͳ���á� 34 /* * MAX_ARG_PAGES������Ϊ�³������ĸ������ͻ�������ʹ�õ�����ڴ�ҳ���� * MAX_ARG_PAGES定义了为新程序分配的给参数和环境变量使用的最大内存页数。 * 32ҳ�ڴ�Ӧ���㹻�ˣ���ʹ�û����Ͳ�����env+arg���ռ���ܺʹﵽ128kB! * 32页内存应该足够了,这使得环境和参数(env+arg)空间的总和达到128kB! */ //// ʹ�ÿ��ļ�ϵͳ���á� //// 使用库文件系统调用。 // ������library
-- ���ļ����� // 参数:library
+- 库文件名。 // Ϊ����ѡ��һ�����ļ������滻���̵�ǰ���ļ�i�ڵ��ֶ�ֵΪ����ָ�����ļ�����i�ڵ� // 为进程选择一个库文件,并替换进程当前库文件i节点字段值为这里指定库文件名的i节点 // ָ�롣���libraryָ��Ϊ�գ���ѽ��̵�ǰ�Ŀ��ļ��ͷŵ��� // 指针。如果library指针为空,则把进程当前的库文件释放掉。 // ���أ��ɹ�����0�����س����롣 // 返回:成功返回0,否则返回出错码。 42 int
sys_uselib(const char * library) 46 // �����жϵ�ǰ�����Ƿ���ͨ���̡�����ͨ���鿴��ǰ���̵Ŀռ䳤���������ġ���Ϊ��ͨ�� // 首先判断当前进程是否普通进程。这是通过查看当前进程的空间长度来做到的。因为普通进 // �̵Ŀռ䳤�ȱ�����ΪTASK_SIZE��64MB�����������������ַ�ռ䳤�Ȳ����� // 程的空间长度被设置为TASK_SIZE(64MB)。因此若进程逻辑地址空间长度不等于TASK_SIZE // �س����루��Ч������������ȡ���ļ�i�ڵ�inode�������ļ���ָ��գ������� // 则返回出错码(无效参数)。否则取库文件i节点inode。若库文件名指针空,则设置inode // ����NULL�� // 等于NULL。 47
if (get_limit(0x17) != namei(library))) &
51
return -ENOENT;
-/* ȡ���ļ�i�ڵ� */ 52
} else 54 /*
we should check filetypes (headers etc), but we don't */ /* ����Ӧ�ü��һ���ļ����ͣ���ͷ����Ϣ�ȣ����������ǻ�û���������� /* 我们应该检查一下文件类型(如头部信息等),但是我们还没有这样做。 */ // Ȼ��Żؽ���ԭ���ļ�i�ڵ㣬��Ԥ�ý��̿�i�ڵ��ֶ�Ϊ�ա�����ȡ�ý��̵Ŀ�������� // 然后放回进程原库文件i节点,并预置进程库i节点字段为空。接着取得进程的库代码所在 // λ�ã����ͷ�ԭ������ҳ������ռ�õ��ڴ�ҳ�档����ý��̿�i�ڵ��ֶ�ָ���¿�i�� // 位置,并释放原库代码的页表和所占用的内存页面。最后让进程库i节点字段指向新库i节 // �㣬������0���ɹ����� // 点,并返回0(成功)。 55
iput(current->library); /* * create_tables()�������������ڴ��н������������Ͳ����ַ������ɴ� * create_tables()函数在新任务内存中解析环境变量和参数字符串,由此 * ����ָ������������ǵĵ�ַ�ŵ�"ջ"�ϣ�Ȼ����ջ��ָ��ֵ�� * 创建指针表,并将它们的地址放到"栈"上,然后返回新栈的指针值。 */ //// ��������ջ�д��������ͻ�������ָ����� //// 在新任务栈中创建参数和环境变量指针表。 // ������p
--���ݶ��в����ͻ�����Ϣƫ��ָ�룻argc - ����������envc
-- �������������� // 参数:p
+-数据段中参数和环境信息偏移指针;argc - 参数个数;envc
+- 环境变量个数。 // ���أ�ջָ��ֵ�� // 返回:栈指针值。 69
static unsigned long * create_tables(char
@@ -2139,27 +2139,27 @@ unsigned long * sp; 73 // ջָ������4�ֽڣ�1�ڣ�Ϊ�߽����Ѱַ�ģ������������ spΪ4��������ֵ����ʱsp // 栈指针是以4字节(1节)为边界进行寻址的,因此这里需让 sp为4的整数倍值。此时sp // λ�ڲ�����������ĩ�ˡ�Ȼ�������Ȱ�sp ���£��͵�ַ�����ƶ�����ջ�пճ��������� // 位于参数环境表的末端。然后我们先把sp 向下(低地址方向)移动,在栈中空出环境变量 // ָ��ռ�õĿռ䣬���û�������ָ��envp ָ��ô�����ճ���һ��λ�������������һ // 指针占用的空间,并让环境变量指针envp 指向该处。多空出的一个位置用于在最后存放一 // ��NULLֵ������ָ���1��sp������ָ������ֽ�ֵ��4�ֽڣ����ٰ�sp�����ƶ����ճ� // 个NULL值。下面指针加1,sp将递增指针宽度字节值(4字节)。再把sp向下移动,空出 // �����в���ָ��ռ�õĿռ䣬����argv ָ��ָ��ô���ͬ������մ���һ��λ�����ڴ�� // 命令行参数指针占用的空间,并让argv 指针指向该处。同样,多空处的一个位置用于存放 // һ��NULLֵ����ʱspָ�����ָ������ʼ�������ǽ�����������ָ��envp�������в� // 一个NULL值。此时sp指向参数指针块的起始处,我们将环境参数块指针envp和命令行参 // ����ָ���Լ������в�������ֵ�ֱ�ѹ��ջ�С� // 数块指针以及命令行参数个数值分别压入栈中。 74
sp = (unsigned long *) (0xfffffffc & (unsigned long) p); 75
sp -= envc+1;
//
-��sp = sp - (envc+1); 76
envp = sp; 81
put_fs_long((unsigned long)argc,--sp); // �ٽ������и�����ָ��ͻ���������ָ��ֱ����ǰ��ճ�������Ӧ�ط������ֱ����һ // 再将命令行各参数指针和环境变量各指针分别放入前面空出来的相应地方,最后分别放置一 // ��NULLָ�롣 // 个NULL指针。 82
while (argc-->0) { 84
while (get_fs_byte(p++)) /*
-nothing */ ; // pָ��ָ����һ���������� 85
} 89
while (get_fs_byte(p++)) /*
-nothing */ ; // pָ��ָ����һ���������� 90
} 92
return sp;
-// ���ع���ĵ�ǰ��ջָ�롣 93 } /* * count()�������������в���/���������ĸ����� * count()函数计算命令行参数/环境变量的个数。 */ //// ������������� //// 计算参数个数。 // ������argv
-- ����ָ�����飬���һ��ָ������NULL�� // 参数:argv
+- 参数指针数组,最后一个指针项是NULL。 // ͳ�Ʋ���ָ��������ָ��ĸ��������ں�����������ָ���ָ������ã���μ����� // 统计参数指针数组中指针的个数。关于函数参数传递指针的指针的作用,请参见程序 // kernel/sched.c�е�171��ǰ��ע�͡� // kernel/sched.c中第171行前的注释。 // ���أ����������� // 返回:参数个数。 98
static int count(char ** */ /* * 'copy_string()'�������û��ڴ�ռ俽������/�����ַ������ں˿���ҳ���С� * 'copy_string()'函数从用户内存空间拷贝参数/环境字符串到内核空闲页面中。 * ��Щ�Ѿ���ֱ�ӷŵ����û��ڴ��еĸ�ʽ�� * 这些已具有直接放到新用户内存中的格式。 * * ��TYT(Tytso)��1991.11.24���ģ�������from_kmem�������ò���ָ���� * 由TYT(Tytso)于1991.11.24日修改,增加了from_kmem参数,该参数指明了 * �ַ������ַ��������������û��λ����ں˶Ρ� * 字符串或字符串数组是来自用户段还是内核段。 * * from_kmem ָ��argv * �ַ��� argv ** * from_kmem 指针argv * 字符串 argv ** *
-0 �û��ռ�
-�û��ռ� *
-1 �ں˿ռ�
-�û��ռ� *
-2 �ں˿ռ�
-�ں˿ռ� * * ������ͨ�������fs�μĴ����������ġ����ڼ���һ���μĴ�������̫�ߣ� * 我们是通过巧妙处理fs段寄存器来操作的。由于加载一个段寄存器代价太高, * �������Ǿ����������set_fs()������ʵ�ڱ�Ҫ�� * 所以我们尽量避免调用set_fs(),除非实在必要。 */ //// ����ָ�������IJ����ַ����������ͻ����ռ��С� //// 复制指定个数的参数字符串到参数和环境空间中。 // ������argc
-- �����ӵIJ���������argv - ����ָ�����飻page -
-�����ͻ����ռ�ҳ��ָ�� // 参数:argc
+- 欲添加的参数个数;argv - 参数指针数组;page -
+参数和环境空间页面指针 // ���顣p
--�������ռ���ƫ��ָ�룬ʼ��ָ���Ѹ��ƴ���ͷ����from_kmem -�ַ�����Դ��־�� // 数组。p
+-参数表空间中偏移指针,始终指向已复制串的头部;from_kmem -字符串来源标志。 // �� do_execve()�����У�p��ʼ��Ϊָ�������(128kB)�ռ�����һ�����ִ��������ַ��� // 在 do_execve()函数中,p初始化为指向参数表(128kB)空间的最后一个长字处,参数字符串 // ���Զ�ջ������ʽ���������и��ƴ�ŵġ���� pָ������Ÿ�����Ϣ�����Ӷ���С�� // 是以堆栈操作方式逆向往其中复制存放的。因此 p指针会随着复制信息的增加而逐渐减小, // ��ʼ��ָ������ַ�����ͷ�����ַ�����Դ��־from_kmemӦ����TYTΪ�˸�execve()���� // 并始终指向参数字符串的头部。字符串来源标志from_kmem应该是TYT为了给execve()增添 // ִ�нű��ļ��Ĺ��ܶ��¼ӵIJ�������û�����нű��ļ��Ĺ���ʱ�����в����ַ��������� // 执行脚本文件的功能而新加的参数。当没有运行脚本文件的功能时,所有参数字符串都在用 // �����ݿռ��С� // 户数据空间中。 // ���أ������ͻ����ռ䵱ǰͷ��ָ�롣��������0�� // 返回:参数和环境空间当前头部指针。若出错则返回0。 127 static unsigned long copy_strings(int
@@ -2458,12 +2458,12 @@ old_fs, new_fs; 133 // ����ȡ��ǰ�μĴ���ds��ָ���ں����ݶΣ���fsֵ���ֱ𱣴浽����new_fs��old_fs�С� // 首先取当前段寄存器ds(指向内核数据段)和fs值,分别保存到变量new_fs和old_fs中。 // ����ַ������ַ������飨ָ�룩�����ں˿ռ䣬������fs�μĴ���ָ���ں����ݶΡ� // 如果字符串和字符串数组(指针)来自内核空间,则设置fs段寄存器指向内核数据段。 134 if (!p) 135
return 0; /* bullet-proofing */
-/* ƫ��ָ����֤ */ 136 new_fs = get_fs(); 138 if (from_kmem==2)
-// ��������ָ�����ں˿ռ�������fsָ���ں˿ռ䡣 139
set_fs(new_fs); // Ȼ��ѭ���������������������һ����������ʼ���ƣ����Ƶ�ָ��ƫ�Ƶ�ַ������ѭ���У� // 然后循环处理各个参数,从最后一个参数逆向开始复制,复制到指定偏移地址处。在循环中, // ����ȡ��Ҫ���Ƶĵ�ǰ�ַ���ָ�롣����ַ������û��ռ���ַ������飨�ַ���ָ�룩�� // 首先取需要复制的当前字符串指针。如果字符串在用户空间而字符串数组(字符串指针)在 // �ں˿ռ䣬������fs�μĴ���ָ���ں����ݶΣ�ds���������ں����ݿռ���ȡ���ַ���ָ�� // 内核空间,则设置fs段寄存器指向内核数据段(ds)。并在内核数据空间中取了字符串指针 // tmp֮������ָ̻�fs�μĴ���ԭֵ��fs��ָ���û��ռ䣩����������fsֵ��ֱ�Ӵ� // tmp之后就立刻恢复fs段寄存器原值(fs再指回用户空间)。否则不用修改fs值而直接从 // �û��ռ�ȡ�ַ���ָ�뵽tmp�� // 用户空间取字符串指针到tmp。 140 while (argc-- >
@@ -2509,8 +2509,8 @@ lang=EN-US> while (argc-- >
141
-if (from_kmem == 1) // ����ָ�����ں˿ռ䣬��fsָ���ں˿ռ䡣 142
@@ -2527,22 +2527,22 @@ lang=EN-US> &nb
145
-if (from_kmem == 1) // ����ָ�����ں˿ռ䣬��fsָ���û��ռ䡣 146
set_fs(old_fs); // Ȼ����û��ռ�ȡ���ַ�����������ò����ַ�������len�� �˺�tmpָ����ַ���ĩ�ˡ� // 然后从用户空间取该字符串,并计算该参数字符串长度len。 此后tmp指向该字符串末端。 // ������ַ������ȳ�����ʱ�����ͻ����ռ��л�ʣ��Ŀ��г��ȣ���ռ䲻���ˡ����ǻָ� // 如果该字符串长度超过此时参数和环境空间中还剩余的空闲长度,则空间不够了。于是恢复 // fs�μĴ���ֵ��������ı�Ļ���������0��������Ϊ�����ͻ����ռ�����128KB������ͨ // fs段寄存器值(如果被改变的话)并返回0。不过因为参数和环境空间留有128KB,所以通 // �������ܷ������������ // 常不可能发生这种情况。 147
@@ -2552,7 +2552,7 @@ remember zero-padding */ 148
do { /*
-����֪��������NULL�ֽڽ�β�� */ 149
@@ -2570,7 +2570,7 @@ this shouldn't happen - 128kB */ 152
set_fs(old_fs);
-/* ���ᷢ��-��Ϊ��128kB�Ŀռ�不会发生-因为有128kB的空间 */ 153 154 } // ����������������ַ��ذ��ַ������Ƶ������ͻ����ռ�ĩ�˴�����ѭ�������ַ������ַ� // 接着我们逆向逐个字符地把字符串复制到参数和环境空间末端处。在循环复制字符串的字符 // �����У���������Ҫ�жϲ����ͻ����ռ�����Ӧλ�ô��Ƿ��Ѿ����ڴ�ҳ�档�����û�о� // 过程中,我们首先要判断参数和环境空间中相应位置处是否已经有内存页面。如果还没有就 // ��Ϊ������1ҳ�ڴ�ҳ�档ƫ����offset������Ϊ��һ��ҳ���еĵ�ǰָ��ƫ��ֵ�� ��Ϊ // 先为其申请1页内存页面。偏移量offset被用作为在一个页面中的当前指针偏移值。 因为 // �տ�ʼִ�б�����ʱ��ƫ�Ʊ���offset����ʼ��Ϊ0������(offset-1
-< 0)�϶�������ʹ�� // 刚开始执行本函数时,偏移变量offset被初始化为0,所以(offset-1
+< 0)肯定成立而使得 // offset���±�����Ϊ��ǰpָ����ҳ�淶Χ�ڵ�ƫ��ֵ�� // offset重新被设置为当前p指针在页面范围内的偏移值。 155
@@ -2612,20 +2612,20 @@ offset = p % PAGE_SIZE; 159
-if (from_kmem==2) // �������ں˿ռ���fsָ���û��ռ䡣 160
set_fs(old_fs); // �����ǰƫ��ֵp���ڵĴ��ռ�ҳ��ָ�������� page[p/PAGE_SIZE] ==0����ʾ��ʱpָ�� // 如果当前偏移值p所在的串空间页面指针数组项 page[p/PAGE_SIZE] ==0,表示此时p指针 // �����Ŀռ��ڴ�ҳ�滹�����ڣ���������һ�����ڴ�ҳ��������ҳ��ָ������ָ�����飬ͬ // 所处的空间内存页面还不存在,则需申请一空闲内存页,并将该页面指针填入指针数组,同 // ʱҲʹҳ��ָ��pagָ�����ҳ�档�����벻������ҳ����0�� // 时也使页面指针pag指向该新页面。若申请不到空闲页面则返回0。 161
@@ -2646,7 +2646,7 @@ return 0; 165
-if (from_kmem==2) // �������ں˿ռ���fsָ���ں˿ռ䡣 166
@@ -2659,8 +2659,8 @@ lang=EN-US> // Ȼ���fs���и����ַ�����1�ֽڵ������ͻ����ռ��ڴ�ҳ��pag��offset���� // 然后从fs段中复制字符串的1字节到参数和环境空间内存页面pag的offset处。 169
@@ -2673,10 +2673,10 @@ lang=EN-US> &nb
171 } // ����ַ������ַ����������ں˿ռ䣬��ָ�fs�μĴ���ԭֵ������ز����ͻ����� // 如果字符串和字符串数组在内核空间,则恢复fs段寄存器原值。最后,返回参数和环境空 // �����Ѹ��Ʋ�����ͷ��ƫ��ֵ�� // 间中已复制参数的头部偏移值。 172 if (from_kmem==2) 176 //// ������ľֲ������������ݡ� //// 修改任务的局部描述符表内容。 // �ľֲ���������LDT���������Ķλ�ַ�Ͷ��������������ͻ����ռ�ҳ����������ݶ� // 修改局部描述符表LDT中描述符的段基址和段限长,并将参数和环境空间页面放置在数据段 // ĩ�ˡ� // 末端。 // ������text_size
-- ִ���ļ�ͷ����a_text�ֶθ����Ĵ���γ���ֵ�� // 参数:text_size
+- 执行文件头部中a_text字段给出的代码段长度值; // page - �����ͻ����ռ�ҳ��ָ�����顣 // page - 参数和环境空间页面指针数组。 // ���أ����ݶ���ֵ��64MB���� // 返回:数据段限长值(64MB)。 177 static unsigned long change_ldt(unsigned
@@ -2726,17 +2726,17 @@ lang=EN-US> int i; 181 // ���ȰѴ�������ݶγ��Ⱦ�����Ϊ64MB�� Ȼ��ȡ��ǰ���ֲ̾���������������������д� // 首先把代码和数据段长度均设置为64MB。 然后取当前进程局部描述符表代码段描述符中代 // ��λ�ַ������λ�ַ�����ݶλ�ַ��ͬ����ʹ����Щ��ֵ�������þֲ����д���κ����� // 码段基址。代码段基址与数据段基址相同。再使用这些新值重新设置局部表中代码段和数据 // ���������еĻ�ַ�Ͷ�����������ע�⣬���ڱ����ص��³���Ĵ�������ݶλ�ַ��ԭ�� // 段描述符中的基址和段限长。这里请注意,由于被加载的新程序的代码和数据段基址与原程 // �����ͬ�����û�б�Ҫ���ظ�ȥ�������ǣ�����186��188���ϵ��������öλ�ַ����� // 序的相同,因此没有必要再重复去设置它们,即第186和188行上的两条设置段基址的语句 // ���࣬��ʡ�ԡ� // 多余,可省略。 182 code_limit = TASK_SIZE; 184 code_base = get_base(current->ldt[1]);
-// include/linux/sched.h����226�� 185 data_base =
@@ -2774,23 +2774,23 @@ style='color:blue'>set_limit(current190 /* make sure fs points to the NEW data segment */ /* Ҫȷ��fs�μĴ�����ָ���µ����ݶ� /* 要确信fs段寄存器已指向新的数据段 */ // fs�μĴ����з���ֲ������ݶ���������ѡ���(0x17)����Ĭ�������fs��ָ���������ݶΡ� // fs段寄存器中放入局部表数据段描述符的选择符(0x17)。即默认情况下fs都指向任务数据段。 191 __asm__("pushl
$0x17\n\tpop %%fs"::); // Ȼ�����ͻ����ռ��Ѵ�����ݵ�ҳ�棨�����MAX_ARG_PAGESҳ��128kB���ŵ����ݶ�ĩ // 然后将参数和环境空间已存放数据的页面(最多有MAX_ARG_PAGES页,128kB)放到数据段末 // �ˡ� �����Ǵӽ��̿ռ�����λ�ÿ�ʼ������һҳһҳ�طš����ļ�����ռ�ý��̿ռ���� // 端。 方法是从进程空间库代码位置开始处逆向一页一页地放。库文件代码占用进程空间最后 // 4MB������put_dirty_page()���ڰ�����ҳ��ӳ�䵽�������ռ��С���mm/memory.c�С� // 4MB。函数put_dirty_page()用于把物理页面映射到进程逻辑空间中。在mm/memory.c中。 192 data_base +=
@@ -2807,7 +2807,7 @@ data_base -= PAGE_SIZE; 195
if (page[i])
-// ����ҳ����ڣ��ͷ��ø�ҳ�档 196
@@ -2818,7 +2818,7 @@ lang=EN-US> } 198 return data_limit;
-// ������ݶ�����64MB���� 199 } /* * 'do_execve()'����ִ��һ���³��� * 'do_execve()'函数执行一个新程序。 */ //// execve()ϵͳ�жϵ��ú��������ز�ִ���ӽ��̣��������� //// execve()系统中断调用函数。加载并执行子进程(其他程序)。 // �ú�����ϵͳ�жϵ��ã�int 0x80�����ܺ�__NR_execve���õĺ����������IJ����ǽ���ϵͳ // 该函数是系统中断调用(int 0x80)功能号__NR_execve调用的函数。函数的参数是进入系统 // ���ô������̺�ֱ�����ñ�ϵͳ���ô������̣�system_call.s��200�У��͵��ñ�����֮ǰ // 调用处理过程后直到调用本系统调用处理过程(system_call.s第200行)和调用本函数之前 // ��system_call.s����203�У���ѹ��ջ�е�ֵ����Щֵ������ // (system_call.s,第203行)逐步压入栈中的值。这些值包括: // �� ��86--88����ѵ�edx��ecx��ebx�Ĵ���ֵ���ֱ��Ӧ**envp��**argv��*filename�� // ① 第86--88行入堆的edx、ecx和ebx寄存器值,分别对应**envp、**argv和*filename; // �� ��94�е���sys_call_table��sys_execve������ָ�룩ʱѹ��ջ�ĺ������ص�ַ��tmp���� // ② 第94行调用sys_call_table中sys_execve函数(指针)时压入栈的函数返回地址(tmp); // �� ��202���ڵ��ñ�����do_execveǰ��ջ��ָ��ջ�е���ϵͳ�жϵij������ָ��eip�� // ③ 第202行在调用本函数do_execve前入栈的指向栈中调用系统中断的程序代码指针eip。 // ������ // 参数: // eip - ����ϵͳ�жϵij������ָ�룬�μ�kernel/system_call.s����ʼ���ֵ�˵���� // eip - 调用系统中断的程序代码指针,参见kernel/system_call.s程序开始部分的说明; // tmp - ϵͳ�ж����ڵ���_sys_execveʱ�ķ��ص�ַ�����ã� // tmp - 系统中断中在调用_sys_execve时的返回地址,无用; // filename - ��ִ�г����ļ���ָ�룻 // filename - 被执行程序文件名指针; // argv - �����в���ָ�������ָ�룻 // argv - 命令行参数指针数组的指针; // envp - ��������ָ�������ָ�롣 // envp - 环境变量指针数组的指针。 // ���أ�������óɹ������أ��������ó����ţ�������-1�� // 返回:如果调用成功,则不返回;否则设置出错号,并返回-1。 207 int do_execve(unsigned long
@@ -2916,59 +2916,59 @@ style='color:blue'>exec ex; 213 unsigned long page[MAX_ARG_PAGES];
-// �����ͻ������ռ�ҳ��ָ�����顣 214 int i,argc,envc; 215 int e_uid, e_gid;
-// ��Ч�û�ID����Ч��ID�� 216 int retval; 217 int sh_bang = 0;
-// �����Ƿ���Ҫִ�нű����� 218 unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4;
-// pָ������ͻ����ռ����� 219 // ����ʽ����ִ���ļ������л���֮ǰ���������ȸ�Щ���¡��ں�����128KB��32��ҳ�棩 // 在正式设置执行文件的运行环境之前,让我们先干些杂事。内核准备了128KB(32个页面) // �ռ�����Ż�ִ���ļ��������в����ͻ����ַ��������а�p��ʼ���ó�λ��128KB�ռ�� // 空间来存放化执行文件的命令行参数和环境字符串。上行把p初始设置成位于128KB空间的 // ���1�����ִ����ڳ�ʼ�����ͻ����ռ�IJ��������У�p������ָ����128KB�ռ��еĵ� // 最后1个长字处。在初始参数和环境空间的操作过程中,p将用来指明在128KB空间中的当 // ǰλ�á� // 前位置。 // ���⣬����eip[1]�ǵ��ñ���ϵͳ���õ�ԭ�û��������μĴ���CSֵ�����еĶ�ѡ��� // 另外,参数eip[1]是调用本次系统调用的原用户程序代码段寄存器CS值,其中的段选择符 // ��Ȼ�����ǵ�ǰ����Ĵ����ѡ�����0x000f���������Ǹ�ֵ����ô CSֻ�ܻ����ں˴��� // 当然必须是当前任务的代码段选择符(0x000f)。若不是该值,那么 CS只能会是内核代码 // �ε�ѡ���
-0x0008�� �����Ǿ��Բ������ģ���Ϊ�ں˴����dz�פ�ڴ�����ܱ��滻���ġ� // 段的选择符
+0x0008。 但这是绝对不允许的,因为内核代码是常驻内存而不能被替换掉的。 // ����������eip[1] ��ֵȷ���Ƿ�������������Ȼ���ٳ�ʼ��128KB�IJ����ͻ������� // 因此下面根据eip[1] 的值确认是否符合正常情况。然后再初始化128KB的参数和环境串空 // �䣬�������ֽ����㣬��ȡ��ִ���ļ���i�ڵ㡣�ٸ��ݺ��������ֱ����������в����� // 间,把所有字节清零,并取出执行文件的i节点。再根据函数参数分别计算出命令行参数和 // �����ַ����ĸ���argc��envc�����⣬ִ���ļ������dz����ļ��� // 环境字符串的个数argc和envc。另外,执行文件必须是常规文件。 220 if ((0xffff &
@@ -3000,12 +3000,12 @@ return -ENOENT; 226 argc = count(argv);
-// ������������� 227 envc = count(envp);
-// �����ַ������������� 228 232
-goto exec_error2; //�����dz����ļ����ó����룬��ת��376�С� 233 } // �����鵱ǰ�����Ƿ���Ȩ����ָ����ִ���ļ���������ִ���ļ�i�ڵ��е����ԣ������� // 下面检查当前进程是否有权运行指定的执行文件。即根据执行文件i节点中的属性,看看本 // �����Ƿ���Ȩִ�������ڰ�ִ���ļ�i�ڵ�������ֶ�ֵȡ��i�к��������Ȳ鿴������ // 进程是否有权执行它。在把执行文件i节点的属性字段值取到i中后,我们首先查看属性中 // �Ƿ������ˡ�����-�û�-ID����set-user_id����־
-�͡�����-��-ID����set-group-id���� // 是否设置了“设置-用户-ID”(set-user_id)标志
+和“设置-组-ID”(set-group-id)标 // ־����������־��Ҫ����һ���û��ܹ�ִ����Ȩ�û����糬���û�root���ij�������ı� // 志。这两个标志主要是让一般用户能够执行特权用户(如超级用户root)的程序,例如改变 // ����ij���passwd�ȡ����set-user-id��־��λ�������ִ�н��̵���Ч�û�ID��euid�� // 密码的程序passwd等。如果set-user-id标志置位,则后面执行进程的有效用户ID(euid) // �����ó�ִ���ļ����û�ID���������óɵ�ǰ���̵�euid�����ִ���ļ�set-group-id�� // 就设置成执行文件的用户ID,否则设置成当前进程的euid。如果执行文件set-group-id被 // ��λ�Ļ�����ִ�н��̵���Ч��ID��egid��������Ϊִ���ļ�����ID���������óɵ�ǰ���� // 置位的话,则执行进程的有效组ID(egid)就设置为执行文件的组ID。否则设置成当前进程 // ��egid��������ʱ���������жϳ�����ֵ�����ڱ���e_uid��e_gid�С� // 的egid。这里暂时把这两个判断出来的值保存在变量e_uid和e_gid中。 234 i =
@@ -3073,28 +3073,28 @@ style='color:blue'>current->egid; // ���ڸ��ݽ��̵�euid��egid��ִ���ļ��ķ������Խ��бȽϡ����ִ���ļ��������н��� // 现在根据进程的euid和egid和执行文件的访问属性进行比较。如果执行文件属于运行进程 // ���û�������ļ�����ֵi����6λ����ʱ�����3λ���ļ������ķ���Ȩ�ޱ�־������� // 的用户,则把文件属性值i右移6位,此时其最低3位是文件宿主的访问权限标志。否则的 // �����ִ���ļ��뵱ǰ���̵��û�����ͬ�飬��ʹ����ֵ���3λ��ִ���ļ����û��ķ��� // 话如果执行文件与当前进程的用户属于同组,则使属性值最低3位是执行文件组用户的访问 // Ȩ�ޱ�־�������ʱ���������3λ���������û����ʸ�ִ���ļ���Ȩ�ޡ� // 权限标志。否则此时属性字最低3位就是其他用户访问该执行文件的权限。 // Ȼ�����Ǹ���������i�����3����ֵ���жϵ�ǰ�����Ƿ���Ȩ���������ִ���ļ������ // 然后我们根据属性字i的最低3比特值来判断当前进程是否有权限运行这个执行文件。如果 // ѡ������Ӧ�û�û�����и��ļ���Ȩ����λ0��ִ��Ȩ�ޣ������������û�Ҳû���κ�Ȩ�� // 选出的相应用户没有运行改文件的权力(位0是执行权限),并且其他用户也没有任何权限 // ���ߵ�ǰ�����û����dz����û����������ǰ����û��Ȩ���������ִ���ļ��������ò��� // 或者当前进程用户不是超级用户,则表明当前进程没有权力运行这个执行文件。于是置不可 // ִ�г����룬����ת��exec_error2��ȥ���˳������� // 执行出错码,并跳转到exec_error2处去作退出处理。 237 if ( 245 } // ����ִ�е����˵����ǰ����������ָ��ִ���ļ���Ȩ�ޡ���˴����↑ʼ������Ҫȡ�� // 程序执行到这里,说明当前进程有运行指定执行文件的权限。因此从这里开始我们需要取出 // ִ���ļ�ͷ�����ݲ��������е���Ϣ�������������л���������������һ��shell������ִ // 执行文件头部数据并根据其中的信息来分析设置运行环境,或者运行另一个shell程序来执 // �нű��������ȶ�ȡִ���ļ���1�����ݵ����ٻ�����С� �����ƻ�������ݵ�ex�С� // 行脚本程序。首先读取执行文件第1块数据到高速缓冲块中。 并复制缓冲块数据到ex中。 // ���ִ���ļ���ʼ�������ֽ����ַ�'#!'����˵��ִ���ļ���һ���ű��ı��ļ���������� // 如果执行文件开始的两个字节是字符'#!',则说明执行文件是一个脚本文本文件。如果想运 // �нű��ļ������Ǿ���Ҫִ�нű��ļ��Ľ��ͳ�������shell����ͨ���ű��ļ��ĵ� // 行脚本文件,我们就需要执行脚本文件的解释程序(例如shell程序)。通常脚本文件的第 // һ���ı�Ϊ��#��/bin/bash������ָ�������нű��ļ���Ҫ�Ľ��ͳ������з����Ǵӽű� // 一行文本为“#!/bin/bash”。它指明了运行脚本文件需要的解释程序。运行方法是从脚本 // �ļ���1�У����ַ�'#!'����ȡ�����еĽ��ͳ�����������IJ��������еĻ�����Ȼ���� // 文件第1行(带字符'#!')中取出其中的解释程序名及后面的参数(若有的话),然后将这 // Щ�����ͽű��ļ����Ž�ִ���ļ�����ʱ�ǽ��ͳ��������в����ռ��С�����֮ǰ���� // 些参数和脚本文件名放进执行文件(此时是解释程序)的命令行参数空间中。在这之前我们 // ��Ȼ��Ҫ�ȰѺ���ָ����ԭ�������в����ͻ����ַ����ŵ�128KB�ռ��У������ィ������ // 当然需要先把函数指定的原有命令行参数和环境字符串放到128KB空间中,而这里建立起来 // �������в�����ŵ�����ǰ��λ�ô�����Ϊ��������ã���������ں�ִ�нű��ļ��Ľ��� // 的命令行参数则放到它们前面位置处(因为是逆向放置)。最后让内核执行脚本文件的解释 // ����������������úý��ͳ���Ľű��ļ����Ȳ�����ȡ�����ͳ����i�ڵ㲢��ת�� // 程序。下面就是在设置好解释程序的脚本文件名等参数后,取出解释程序的i节点并跳转到 // 229��ȥִ�н��ͳ�������������Ҫ��ת��ִ�й��Ĵ���229��ȥ�����������ȷ�ϲ��� // 229行去执行解释程序。由于我们需要跳转到执行过的代码229行去,因此在下面确认并处 // ���˽ű��ļ�֮����Ҫ����һ����ֹ�ٴ�ִ������Ľű����������־sh_bang ���ں���� // 理了脚本文件之后需要设置一个禁止再次执行下面的脚本处理代码标志sh_bang 。在后面的 // �����иñ�־Ҳ������ʾ�����Ѿ����ú�ִ���ļ��������в�������Ҫ�ظ����á� // 代码中该标志也用来表示我们已经设置好执行文件的命令行参数,不要重复设置。 246 if (!(bh = &n
/* *
-�ⲿ�ִ�����'#!'�Ľ��ͣ���Щ���ӣ���ϣ���ܹ�����-TYT
*/ 259 // �����↑ʼ�����Ǵӽű��ļ�����ȡ���ͳ�����������������ѽ��ͳ����������ͳ���IJ��� // 从这里开始,我们从脚本文件中提取解释程序名及其参数,并把解释程序名、解释程序的参数 // �ͽű��ļ�����Ϸ��뻷���������С����ȸ��ƽű��ļ�ͷ1���ַ�'#!'������ַ�����buf // 和脚本文件名组合放入环境参数块中。首先复制脚本文件头1行字符'#!'后面的字符串到buf // �У����к��нű����ͳ�����������/bin/sh����Ҳ���ܻ��������ͳ���ļ���������Ȼ��� // 中,其中含有脚本解释程序名(例如/bin/sh),也可能还包含解释程序的几个参数。然后对 // buf�е����ݽ��д�����ɾ����ʼ�Ŀո��Ʊ����� // buf中的内容进行处理。删除开始的空格、制表符。 260
@@ -3256,7 +3256,7 @@ lang=EN-US> &nb
262
iput(inode);
-// �ͷŻ���鲢�Żؽű��ļ�i�ڵ㡣 263
@@ -3269,8 +3269,8 @@ style='color:blue'>buf, '\n')) { 265
-*cp = '\0'; // ��1�����з�����NULL��ȥ���ո��Ʊ����� 266
@@ -3283,7 +3283,7 @@ lang=EN-US> &nb
268
-if (!cp || *cp == '\0') { // ������û���������ݣ�������� 269
@@ -3292,20 +3292,20 @@ No interpreter name found */ 270
-goto exec_error1; /* û���ҵ��ű����ͳ�����没有找到脚本解释程序名 */ 271
} // ��ʱ���ǵõ��˿�ͷ�ǽű����ͳ�������һ�����ݣ��ַ�����������������С�����ȡ��һ�� // 此时我们得到了开头是脚本解释程序名的一行内容(字符串)。下面分析该行。首先取第一个 // �ַ�������Ӧ���ǽ��ͳ���������ʱi_nameָ������ơ������ͳ����������ַ���������Ӧ // 字符串,它应该是解释程序名,此时i_name指向该名称。若解释程序名后还有字符,则它们应 // ���ǽ��ͳ���IJ�������������i_argָ��ô��� // 该是解释程序的参数串,于是令i_arg指向该串。 272
@@ -3339,12 +3339,12 @@ if (*cp) { 279
*cp++ = '\0';
-// ���ͳ�����β����NULL�ַ��� 280
i_arg = cp;
-// i_argָ����ͳ�������� 281
@@ -3369,49 +3369,49 @@ lang=EN-US> &n
/*
-* OK�������Ѿ����������ͳ�����ļ����Լ�(��ѡ��)������
*/ // ��������Ҫ��������������Ľ��ͳ�����i_name �������i_arg �ͽű��ļ�����Ϊ���ͳ� // 现在我们要把上面解析出来的解释程序名i_name 及其参数i_arg 和脚本文件名作为解释程 // ��IJ����Ž������Ͳ������С���������������Ҫ�Ѻ����ṩ��ԭ��һЩ�����ͻ����ַ��� // 序的参数放进环境和参数块中。不过首先我们需要把函数提供的原来一些参数和环境字符串 // �ȷŽ�ȥ��Ȼ���ٷ�������������ġ�������������в�����˵�����ԭ���IJ����� // 先放进去,然后再放这里解析出来的。例如对于命令行参数来说,如果原来的参数是"-arg1 // -arg2"�����ͳ�������"bash"���������"-iarg1
--iarg2"���ű��ļ�������ԭ����ִ���� // -arg2"、解释程序名是"bash"、其参数是"-iarg1
+-iarg2"、脚本文件名(即原来的执行文 // ��������"example.sh"����ô�ڷ�������IJ���֮���µ������������������� // 件名)是"example.sh",那么在放入这里的参数之后,新的命令行类似于这样:
-// ��bash
+// “bash
-iarg1 -iarg2 example.sh -arg1 -arg2�� // �������ǰ�sh_bang��־���ϣ�Ȼ��Ѻ��������ṩ��ԭ�в����ͻ����ַ������뵽�ռ��С� // 这里我们把sh_bang标志置上,然后把函数参数提供的原有参数和环境字符串放入到空间中。 // �����ַ����Ͳ��������ֱ���envc ��argc-1�����ٸ��Ƶ�һ��ԭ�в�����ԭ����ִ���ļ� // 环境字符串和参数个数分别是envc 和argc-1个。少复制的一个原有参数是原来的执行文件 // ����������Ľű��ļ�����[[?? ���Կ�����ʵ�������Dz���Ҫȥ���д����ű��ļ��������� // 名,即这里的脚本文件名。[[?? 可以看出,实际上我们不需要去另行处理脚本文件名,即这 // ����ȫ���Ը���argc������������ԭ��ִ���ļ����������ڵĽű��ļ���������Ϊ��λ��ͬ // 里完全可以复制argc个参数,包括原来执行文件名(即现在的脚本文件名)。因为它位于同 // һ��λ����
-]]��ע�⣡����ָ��p���Ÿ�����Ϣ���Ӷ�����С��ַ�����ƶ������������ // 一个位置上
+]]。注意!这里指针p随着复制信息增加而逐渐向小地址方向移动,因此这两个 // ���ƴ�����ִ���������������Ϣ��λ�ڳ��������в�������Ϣ����Ϸ�������
-pָ�� // 复制串函数执行完后,环境参数串信息块位于程序命令行参数串信息块的上方,并且
+p指向 // ����ĵ�1����������copy_strings()���һ��������0��ָ�������ַ������û��ռ䡣 // 程序的第1个参数串。copy_strings()最后一个参数(0)指明参数字符串在用户空间。 286
@@ -3465,37 +3465,37 @@ lang=EN-US> &n
/*
-* ƴ�� (1) argv[0]�зŽ��ͳ��������
-* (2) (��ѡ��)���ͳ���IJ���
-* (3) �ű����������
*
-* ������������д����ģ��������û������Ͳ����Ĵ�ŷ�ʽ��ɵġ�
*/ // �������������ƽű��ļ��������ͳ���IJ����ͽ��ͳ����ļ����������ͻ����ռ��С� // 接着我们逆向复制脚本文件名、解释程序的参数和解释程序文件名到参数和环境空间中。 // �����������ó����룬��ת��exec_error1�����⣬���ڱ����������ṩ�Ľű��ļ��� // 若出错,则置出错码,跳转到exec_error1。另外,由于本函数参数提供的脚本文件名 // filename���û��ռ䣬�����︳��copy_strings()�Ľű��ļ�����ָ�����ں˿ռ䣬�� // filename在用户空间,但这里赋予copy_strings()的脚本文件名的指针在内核空间,因 // ����������ַ������������һ���������ַ�����Դ��־����Ҫ�����ó�1�����ַ����� // 此这个复制字符串函数的最后一个参数(字符串来源标志)需要被设置成1。若字符串在 // �ں˿ռ䣬��copy_strings()�����һ������Ҫ���ó�2��������ĵ�301��304�С� // 内核空间,则copy_strings()的最后一个参数要设置成2,如下面的第301、304行。 298
@@ -3508,7 +3508,7 @@ lang=EN-US> &n
300
if (i_arg) {
-// ���ƽ��ͳ���Ķ�������� 301
@@ -3563,31 +3563,31 @@ lang=EN-US> &n
/*
-* OK������ʹ�ý��ͳ����i�ڵ��������̡�
*/ // �������ȡ�ý��ͳ����i�ڵ�ָ�룬Ȼ����ת��204��ȥִ�н��ͳ���Ϊ�˻�ý��ͳ� // 最后我们取得解释程序的i节点指针,然后跳转到204行去执行解释程序。为了获得解释程 // ���i�ڵ㣬������Ҫʹ��namei()���������Ǹú�����ʹ�õIJ������ļ������Ǵ��û��� // 序的i节点,我们需要使用namei()函数,但是该函数所使用的参数(文件名)是从用户数 // �ݿռ�õ��ģ����ӶμĴ���fs��ָ�ռ���ȡ�á�����ڵ���namei()����֮ǰ������Ҫ // 据空间得到的,即从段寄存器fs所指空间中取得。因此在调用namei()函数之前我们需要 // ����ʱ��fsָ���ں����ݿռ䣬���ú����ܴ��ں˿ռ�õ����ͳ����������� // 先临时让fs指向内核数据空间,以让函数能从内核空间得到解释程序名,并在namei() // ���غ�ָ�fs��Ĭ�����á����������������ʱ����ԭfs�μĴ�����ԭָ���û����ݶΣ� // 返回后恢复fs的默认设置。因此这里我们先临时保存原fs段寄存器(原指向用户数据段) // ��ֵ���������ó�ָ���ں����ݶΣ�Ȼ��ȡ���ͳ����i�ڵ㡣֮���ٻָ�fs��ԭֵ���� // 的值,将其设置成指向内核数据段,然后取解释程序的i节点。之后再恢复fs的原值。并 // ��ת��restart_interp��204�У������´����µ�ִ���ļ� -- �ű��ļ��Ľ��ͳ��� // 跳转到restart_interp(204行)处重新处理新的执行文件 -- 脚本文件的解释程序。 313
@@ -3605,7 +3605,7 @@ if (!(inode=namei(interp))) {
316
set_fs(old_fs);
-/* ȡ�ý��ͳ����i�ڵ� */ 317
@@ -3632,27 +3632,27 @@ lang=EN-US> } // ��ʱ������е�ִ���ļ�ͷ�ṹ�����Ѿ����Ƶ���ex �С� �������ͷŸû���飬����ʼ�� // 此时缓冲块中的执行文件头结构数据已经复制到了ex 中。 于是先释放该缓冲块,并开始对 // ex�е�ִ��ͷ��Ϣ�����жϴ���������Linux 0.12�ں���˵������֧��ZMAGICִ���ļ��� // ex中的执行头信息进行判断处理。对于Linux 0.12内核来说,它仅支持ZMAGIC执行文件格 // ʽ������ִ���ļ����붼������ַ0 ��ʼִ�У���˲�֧�ֺ��д���������ض�λ��Ϣ�� // 式,并且执行文件代码都从逻辑地址0 开始执行,因此不支持含有代码或数据重定位信息的 // ִ���ļ�����Ȼ�����ִ���ļ�ʵ��̫�����ִ���ļ���ȱ��ȫ����ô����Ҳ������������ // 执行文件。当然,如果执行文件实在太大或者执行文件残缺不全,那么我们也不能运行它。 // ��˶��������������ִ�г������ִ���ļ���������ҳ��ִ���ļ���ZMAGIC�������ߴ� // 因此对于下列情况将不执行程序:如果执行文件不是需求页可执行文件(ZMAGIC)、或者代 // ��������ض�λ���ֳ��Ȳ�����0������(�����+���ݶ�+��) ���ȳ���50MB������ִ���ļ� // 码和数据重定位部分长度不等于0、或者(代码段+数据段+堆) 长度超过50MB、或者执行文件 // ����С��
-(�����+���ݶ�+���ű�����+ִ��ͷ����) ���ȵ��ܺ͡� // 长度小于
+(代码段+数据段+符号表长度+执行头部分) 长度的总和。 323 329 } // ���⣬���ִ���ļ��д��뿪ʼ��û��λ��1��ҳ�棨1024�ֽڣ��߽紦����Ҳ����ִ�С� // 另外,如果执行文件中代码开始处没有位于1个页面(1024字节)边界处,则也不能执行。 // ��Ϊ����ҳ��Demand paging������Ҫ�����ִ���ļ�����ʱ��ҳ��Ϊ��λ�����Ҫ��ִ�� // 因为需求页(Demand paging)技术要求加载执行文件内容时以页面为单位,因此要求执行 // �ļ�ӳ���д�������ݶ���ҳ��߽紦��ʼ�� // 文件映像中代码和数据都从页面边界处开始。 330 if ( 334 } // ���sh_bang��־û�����ã�����ָ�������������в����ͻ����ַ����������ͻ����ռ� // 如果sh_bang标志没有设置,则复制指定个数的命令行参数和环境字符串到参数和环境空间 // �С���sh_bang��־�Ѿ����ã�������ǽ����нű����ͳ���ʱ��������ҳ���Ѿ����ƣ� // 中。若sh_bang标志已经设置,则表明是将运行脚本解释程序,此时环境变量页面已经复制, // �����ٸ��ơ�ͬ������sh_bangû����λ����Ҫ���ƵĻ�����ô��ʱָ��p���Ÿ�����Ϣ�� // 无须再复制。同样,若sh_bang没有置位而需要复制的话,那么此时指针p随着复制信息增 // �Ӷ�����С��ַ�����ƶ���������������ƴ�����ִ���������������Ϣ��λ�ڳ��� // 加而逐渐向小地址方向移动,因此这两个复制串函数执行完后,环境参数串信息块位于程序 // ��������Ϣ����Ϸ�������pָ�����ĵ�1������������ʵ�ϣ�p��128KB�����ͻ����� // 参数串信息块的上方,并且p指向程序的第1个参数串。事实上,p是128KB参数和环境空 // ���е�ƫ��ֵ��������p=0�����ʾ��������������ռ�ҳ���Ѿ���ռ�������ɲ����ˡ� // 间中的偏移值。因此如果p=0,则表示环境变量与参数空间页面已经被占满,容纳不下了。 335 if (!sh_bang) { /* OK�����濪ʼ��û�з��صĵط��� /* OK,下面开始就没有返回的地方了 */ // ǰ��������Ժ��������ṩ����Ϣ����Ҫ����ִ���ļ��������в����ͻ����ռ���������ã� // 前面我们针对函数参数提供的信息对需要运行执行文件的命令行参数和环境空间进行了设置, // ����û��Ϊִ���ļ�����ʲôʵ���ԵĹ���������û������Ϊִ���ļ���ʼ����������ṹ // 但还没有为执行文件做过什么实质性的工作,即还没有做过为执行文件初始化进程任务结构 // ��Ϣ������ҳ���ȹ������������Ǿ�������Щ����������ִ���ļ�ֱ��ʹ�õ�ǰ���̵ġ��� // 信息、建立页表等工作。现在我们就来做这些工作。由于执行文件直接使用当前进程的“躯 // �ǡ�������ǰ���̽��������ִ���ļ��Ľ��̣����������Ҫ�����ͷŵ�ǰ����ռ�õ�ijЩ // 壳”,即当前进程将被改造成执行文件的进程,因此我们需要首先释放当前进程占用的某些 // ϵͳ��Դ�������ر�ָ�����Ѵ��ļ���ռ�õ�ҳ�����ڴ�ҳ��ȡ�Ȼ�����ִ���ļ�ͷ�� // 系统资源,包括关闭指定的已打开文件、占用的页表和内存页面等。然后根据执行文件头结 // ����Ϣ�ĵ�ǰ����ʹ�õľֲ���������LDT�������������ݣ��������ô���κ����ݶ��� // 构信息修改当前进程使用的局部描述符表LDT中描述符的内容,重新设置代码段和数据段描 // ����������������ǰ�洦���õ���e_uid��e_gid����Ϣ�����ý�������ṹ����ص��� // 述符的限长,再利用前面处理得到的e_uid和e_gid等信息来设置进程任务结构中相关的字 // �Ρ�����ִ�б���ϵͳ���ó���ķ��ص�ַ eip[]ָ��ִ���ļ��д������ʼλ�ô����� // 段。最后把执行本次系统调用程序的返回地址 eip[]指向执行文件中代码的起始位置处。这 // ������ϵͳ�����˳����غ�ͻ�ȥ������ִ���ļ��Ĵ����ˡ�ע�⣬��Ȼ��ʱ��ִ���ļ��� // 样当本系统调用退出返回后就会去运行新执行文件的代码了。注意,虽然此时新执行文件代 // ������ݻ�û�д��ļ��м��ص��ڴ��У���������ͻ������Ѿ���copy_strings() ��ʹ�� // 码和数据还没有从文件中加载到内存中,但其参数和环境块已经在copy_strings() 中使用 // get_free_page()�����������ڴ�ҳ���������ݣ�����change_ldt()������ʹ��put_page() // get_free_page()分配了物理内存页来保存数据,并在change_ldt()函数中使用put_page() // ���˽������ռ��ĩ�˴������⣬��create_tables()��Ҳ���������û�ջ�ϴ�Ų��� // 到了进程逻辑空间的末端处。另外,在create_tables()中也会由于在用户栈上存放参数 // �ͻ���ָ���������ȱҳ�쳣���Ӷ��ڴ��������Ҳ��ʹ�Ϊ�û�ջ�ռ�ӳ�������ڴ�ҳ�� // 和环境指针表而引起缺页异常,从而内存管理程序也会就此为用户栈空间映射物理内存页。 // // �����������ȷŻؽ���ԭִ�г����i�ڵ㣬�����ý���executable �ֶ�ָ����ִ���ļ� // 这里我们首先放回进程原执行程序的i节点,并且让进程executable 字段指向新执行文件 // ��i�ڵ㡣Ȼ��λԭ���̵������źŴ��������������SIG_IGN������븴λ���ٸ����� // 的i节点。然后复位原进程的所有信号处理句柄,但对于SIG_IGN句柄无须复位。再根据设 // ����ִ��ʱ�ر��ļ������close_on_exec��λͼ��־���ر�ָ���Ĵ��ļ�����λ�ñ�־�� // 定的执行时关闭文件句柄(close_on_exec)位图标志,关闭指定的打开文件并复位该标志。 345 if ( &nb
lang=EN-US> current->close_on_exec = 0; // Ȼ����ݵ�ǰ����ָ���Ļ���ַ�������ͷ�ԭ������Ĵ���κ����ݶ�����Ӧ���ڴ�ҳ�� // 然后根据当前进程指定的基地址和限长,释放原来程序的代码段和数据段所对应的内存页表 // ָ���������ڴ�ҳ�漰ҳ����������ʱ��ִ���ļ���û��ռ�����ڴ����κ�ҳ�棬����ڴ� // 指定的物理内存页面及页表本身。此时新执行文件并没有占用主内存区任何页面,因此在处 // ��������������ִ���ļ�����ʱ�ͻ�����ȱҳ�쳣�жϣ���ʱ�ڴ��������ִ��ȱҳ�� // 理器真正运行新执行文件代码时就会引起缺页异常中断,此时内存管理程序即会执行缺页处 // ����Ϊ��ִ���ļ������ڴ�ҳ����������ҳ������Ұ����ִ���ļ�ҳ������ڴ��С� // 理而为新执行文件申请内存页面和设置相关页表项,并且把相关执行文件页面读入内存中。 // ������ϴ�����ʹ����Э��������ָ����ǵ�ǰ���̣������ÿգ�����λʹ����Э������ // 如果“上次任务使用了协处理器”指向的是当前进程,则将其置空,并复位使用了协处理器 // �ı�־�� // 的标志。 359 NULL; // Ȼ�����Ǹ�����ִ���ļ�ͷ�ṹ�еĴ��볤���ֶ� a_text ��ֵ�ľֲ�������������ַ�� // 然后我们根据新执行文件头结构中的代码长度字段 a_text 的值修改局部表中描述符基址和 // ����������128KB �IJ����ͻ����ռ�ҳ����������ݶ�ĩ�ˡ�ִ���������֮��p��ʱ // 段限长,并将128KB 的参数和环境空间页面放置在数据段末端。执行下面语句之后,p此时 // ���ij������ݶ���ʼ��Ϊԭ���ƫ��ֵ������ָ������ͻ����ռ����ݿ�ʼ��������ת���� // 更改成以数据段起始处为原点的偏移值,但仍指向参数和环境空间数据开始处,即已转换成 // Ϊջָ��ֵ��Ȼ������ڲ�����create_tables() ��ջ�ռ��д��������Ͳ�������ָ����� // 为栈指针值。然后调用内部函数create_tables() 在栈空间中创建环境和参数变量指针表, // �������main()��Ϊ����ʹ�ã������ظ�ջָ�롣 // 供程序的main()作为参数使用,并返回该栈指针。 364 p += p = (unsigned long)
// �������Ľ��̸��ֶ�ֵΪ��ִ���ļ�����Ϣ�������������ṹ����β�ֶ�end_code�� // 接着再修改进程各字段值为新执行文件的信息。即令进程任务结构代码尾字段end_code等 // ��ִ���ļ��Ĵ���γ��� a_text������β�ֶ� end_data ����ִ���ļ��Ĵ���γ��ȼ��� // 于执行文件的代码段长度 a_text;数据尾字段 end_data 等于执行文件的代码段长度加数 // �ݶγ��ȣ�a_data
-+ a_text����������̶ѽ�β�ֶ�brk = a_text + a_data + a_bss�� // 据段长度(a_data
++ a_text);并令进程堆结尾字段brk = a_text + a_data + a_bss。 // brk����ָ�����̵�ǰ���ݶΣ�����δ��ʼ�����ݲ��֣�ĩ��λ�ã����ں�Ϊ���̷����ڴ� // brk用于指明进程当前数据段(包括未初始化数据部分)末端位置,供内核为进程分配内存 // ʱָ�����俪ʼλ�á�Ȼ�����ý���ջ��ʼ�ֶ�Ϊջָ������ҳ�棬���������ý��̵���Ч // 时指定分配开始位置。然后设置进程栈开始字段为栈指针所在页面,并重新设置进程的有效 // �û�id����Ч��id�� // 用户id和有效组id。 367 current->sgid = current->egid
= e_gid; // ���ԭ����ϵͳ�жϵij����ڶ�ջ�ϵĴ���ָ���滻Ϊָ����ִ�г������ڵ㣬����ջ // 最后将原调用系统中断的程序在堆栈上的代码指针替换为指向新执行程序的入口点,并将栈 // ָ���滻Ϊ��ִ���ļ���ջָ�롣�˺�ָ�������Щջ���ݲ�ʹ��CPUȥִ����ִ�� // 指针替换为新执行文件的栈指针。此后返回指令将弹出这些栈数据并使得CPU去执行新执行 // �ļ�����˲��᷵�ص�ԭ����ϵͳ�жϵij�����ȥ�ˡ� // 文件,因此不会返回到原调用系统中断的程序中去了。 373 eip[0] =
ex.a_entry; /* eip, magic happens :-) */
-/* eip��ħ����������*/ 374 eip[3] =
p; /*
stack pointer */ /*
-esp����ջָ�� */ 375 return 0; 377 iput(inode);
-// �Ż�i�ڵ㡣 378 exec_error1: 380
free_page(page[i]);
-// �ͷŴ�Ų����ͻ��������ڴ�ҳ�档 381 return(retval);
- // ���س����롣 382 } 6 7
-#include <errno.h> // �����ͷ�ļ�������ϵͳ�и��ֳ����š� 8
-#include <sys/stat.h> // �ļ�״̬ͷ�ļ��������ļ�״̬�ṹstat{}�ͳ����� 9 10
-#include <linux/fs.h> // �ļ�ϵͳͷ�ļ��������ļ����ṹ��file��m_inode���ȡ� 11
-#include <linux/sched.h> // ���ȳ���ͷ�ļ�������������ṹtask_struct������0���ݵȡ� 12
-#include <linux/kernel.h> // �ں�ͷ�ļ�������һЩ�ں˳��ú�����ԭ�ζ��塣 13
-#include <asm/segment.h> // �β���ͷ�ļ����������йضμĴ���������Ƕ��ʽ��ຯ���� 14 //// �����ļ�״̬��Ϣ�� //// 复制文件状态信息。 // ����inode���ļ�i�ڵ㣬statbuf���û����ݿռ���stat�ļ�״̬�ṹָ�룬���ڴ��ȡ // 参数inode是文件i节点,statbuf是用户数据空间中stat文件状态结构指针,用于存放取 // �õ�״̬��Ϣ�� // 得的状态信息。 15
static void cp_stat(struct 19 // ������֤(�����)������ݵ��ڴ�ռ䡣Ȼ����ʱ������Ӧ�ڵ��ϵ���Ϣ�� // 首先验证(或分配)存放数据的内存空间。然后临时复制相应节点上的信息。 20
verify_area(statbuf,sizeof (struct stat)); 21
-tmp.st_dev = inode->i_dev; // �ļ����ڵ��豸�š� 22
-tmp.st_ino = inode->i_num; // �ļ�i�ڵ�š� 23
-tmp.st_mode = inode->i_mode; // �ļ����ԡ� 24
-tmp.st_nlink = inode->i_nlinks; // ��������� 25
-tmp.st_uid = inode->i_uid; // �ļ����û�ID�� 26
-tmp.st_gid = inode->i_gid; // �����ID�� 27
-tmp.st_rdev = inode->i_zone[0]; // �豸�ţ����������ַ��ļ�����豸�ļ����� 28
-tmp.st_size = inode->i_size; // �ļ��ֽڳ��ȣ�����ļ��dz����ļ����� 29
-tmp.st_atime = inode->i_atime; // ������ʱ�䡣 30
-tmp.st_mtime = inode->i_mtime; // �����ʱ�䡣 31
-tmp.st_ctime = inode->i_ctime; // ���i�ڵ���ʱ�䡣 // �����Щ״̬��Ϣ���Ƶ��û��������С� // 最后将这些状态信息复制到用户缓冲区中。 32
for (i=0 ; i<sizeof (tmp) ; i++) 35 //// �ļ�״̬ϵͳ���á� //// 文件状态系统调用。 // ���ݸ������ļ�����ȡ����ļ�״̬��Ϣ�� // 根据给定的文件名获取相关文件状态信息。 // ����filename��ָ�����ļ�����statbuf�Ǵ��״̬��Ϣ�Ļ�����ָ�롣 // 参数filename是指定的文件名,statbuf是存放状态信息的缓冲区指针。 // ���أ��ɹ�����0���������س����롣 // 返回:成功返回0,若出错则返回出错码。 36 int
sys_stat(char * filename, struct m_inode * inode; 39 // ���ȸ����ļ����ҳ���Ӧ��i�ڵ㡣Ȼ��i�ڵ��ϵ��ļ�״̬��Ϣ���Ƶ��û��������У� // 首先根据文件名找出对应的i节点。然后将i节点上的文件状态信息复制到用户缓冲区中, // ���Żظ�i�ڵ㡣 // 并放回该i节点。 40
if (!(inode=namei(filename))) 46 //// �ļ�״̬ϵͳ���á� //// 文件状态系统调用。 // ���ݸ������ļ�����ȡ����ļ�״̬��Ϣ���ļ�·�������з��������ļ�������ȡ�����ļ� // 根据给定的文件名获取相关文件状态信息。文件路径名中有符号链接文件名,则取符号文件 // ��״̬�� // 的状态。 // ����filename��ָ�����ļ�����statbuf�Ǵ��״̬��Ϣ�Ļ�����ָ�롣 // 参数filename是指定的文件名,statbuf是存放状态信息的缓冲区指针。 // ���أ��ɹ�����0���������س����롣 // 返回:成功返回0,若出错则返回出错码。 47 int
sys_lstat(char * filename, struct m_inode * inode; 50 // ���ȸ����ļ����ҳ���Ӧ��i�ڵ㡣Ȼ��i�ڵ��ϵ��ļ�״̬��Ϣ���Ƶ��û��������У� // 首先根据文件名找出对应的i节点。然后将i节点上的文件状态信息复制到用户缓冲区中, // ���Żظ�i�ڵ㡣 // 并放回该i节点。 51
if (!(inode = lnamei(filename)))
-// ȡָ��·����i�ڵ㣬������������ӡ� 52
return -ENOENT; 57 //// �ļ�״̬ϵͳ���á� //// 文件状态系统调用。 // ���ݸ������ļ������ȡ����ļ�״̬��Ϣ�� // 根据给定的文件句柄获取相关文件状态信息。 // ����fd��ָ���ļ��ľ��(������)��statbuf�Ǵ��״̬��Ϣ�Ļ�����ָ�롣 // 参数fd是指定文件的句柄(描述符),statbuf是存放状态信息的缓冲区指针。 // ���أ��ɹ�����0���������س����롣 // 返回:成功返回0,若出错则返回出错码。 58 int
sys_fstat(unsigned int fd, struct m_inode * inode; 62 // ����ȡ�ļ������Ӧ���ļ��ṹ��Ȼ����еõ��ļ���i�ڵ㡣Ȼ��i�ڵ��ϵ��ļ�״ // 首先取文件句柄对应的文件结构,然后从中得到文件的i节点。然后将i节点上的文件状 // ̬��Ϣ���Ƶ��û��������С�����ļ����ֵ����һ�����������ļ���NR_OPEN���� // 态信息复制到用户缓冲区中。如果文件句柄值大于一个程序最多打开文件数NR_OPEN,或 // �߸þ�����ļ��ṹָ��Ϊ�գ����߶�Ӧ�ļ��ṹ��i�ڵ��ֶ�Ϊ�գ�����������س��� // 者该句柄的文件结构指针为空,或者对应文件结构的i节点字段为空,则出错,返回出错 // �벢�˳��� // 码并退出。 63
if (fd >= NR_OPEN || !(f= 68 //// �����������ļ�ϵͳ���á� //// 读符号链接文件系统调用。 // �õ��ö�ȡ���������ļ������ݣ����÷���������ָ���ļ���·�����ַ����������ŵ�ָ�� // 该调用读取符号链接文件的内容(即该符号链接所指向文件的路径名字符串),并放到指定 // ���ȵ��û��������С���������̫С���ͻ�ضϷ������ӵ����ݡ� // 长度的用户缓冲区中。若缓冲区太小,就会截断符号链接的内容。 // ������path
--- ���������ļ�·������buf -- �û���������bufsiz
--- ���������ȡ� // 参数:path
+-- 符号链接文件路径名;buf -- 用户缓冲区;bufsiz
+-- 缓冲区长度。 // ���أ��ɹ��ط��뻺�����е��ַ�������ʧ���س����롣 // 返回:成功则返回放入缓冲区中的字符数;若失败则返回出错码。 69 int
sys_readlink(const char * path, char * 75 // ���ȼ�����֤������������Ч�ԣ���������е������û��������ֽڳ���bufsi������ // 首先检查和验证函数参数的有效性,并对其进行调整。用户缓冲区字节长度bufsi必须在 // 1--1023֮�䡣Ȼ��ȡ�÷��������ļ�����i�ڵ㣬����ȡ���ļ��ĵ�1���������ݡ�֮ // 1--1023之间。然后取得符号链接文件名的i节点,并读取该文件的第1块数据内容。之 // ��Ż�i�ڵ㡣 // 后放回i节点。 76
if (bufsiz <= 0) 87
iput(inode); // �����ȡ�ļ��������ݳɹ�����������и������bufsiz���ַ����û��������С������� // 如果读取文件数据内容成功,则从内容中复制最多bufsiz个字符到用户缓冲区中。不复制 // NULL�ַ�������ͷŻ���飬�����ظ��Ƶ��ֽ����� // NULL字符。最后释放缓冲块,并返回复制的字节数。 88
if (!bh) 6 7
-#include <string.h> // �ַ���ͷ�ļ�����Ҫ������һЩ�й��ַ���������Ƕ�뺯���� 8
-#include <errno.h> // �����ͷ�ļ�������ϵͳ�и��ֳ����š� 9
-#include <linux/sched.h> // ���ȳ���ͷ�ļ�������������ṹtask_struct������0���ݵȡ� 10
-#include <linux/kernel.h> // �ں�ͷ�ļ�������һЩ�ں˳��ú�����ԭ�ζ��塣 11
-#include <asm/segment.h> // �β���ͷ�ļ����������йضμĴ���������Ƕ��ʽ��ຯ���� 12 13
-#include <fcntl.h> // �ļ�����ͷ�ļ��������ļ������������IJ������Ƴ������š� 14
-#include <sys/stat.h> // �ļ�״̬ͷ�ļ��������ļ�״̬�ṹstat{}�ͳ����� 15 16
extern int sys_close(int fd);
-// �ر��ļ�ϵͳ���á�(fs/open.c, 192) 17 //// �����ļ�������ļ����������� //// 复制文件句柄(文件描述符)。 // ����fd�������Ƶ��ļ������argָ�����ļ��������С��ֵ�� // 参数fd是欲复制的文件句柄,arg指定新文件句柄的最小数值。 // �������ļ����������롣 // 返回新文件句柄或出错码。 18
static int dupfd(unsigned int fd,
@@ -1893,13 +1893,13 @@ unsigned int arg) 19 { // ���ȼ�麯����������Ч�ԡ�����ļ����ֵ����һ�����������ļ���NR_OPEN������ // 首先检查函数参数的有效性。如果文件句柄值大于一个程序最多打开文件数NR_OPEN,或者 // �þ�����ļ��ṹ�����ڣ��س����벢�˳������ָ�����¾��ֵarg���������� // 该句柄的文件结构不存在,则返回出错码并退出。如果指定的新句柄值arg大于最多打开文 // ������Ҳ���س����벢�˳���ע�⣬ʵ�����ļ�������ǽ����ļ��ṹָ�������������š� // 件数,也返回出错码并退出。注意,实际上文件句柄就是进程文件结构指针数组项索引号。 20
if (fd >= NR_OPEN || !NR_OPEN) 23
return -EINVAL; // Ȼ���ڵ�ǰ���̵��ļ��ṹָ��������Ѱ�������ŵ��ڻ����arg������û��ʹ�õ���� // 然后在当前进程的文件结构指针数组中寻找索引号等于或大于arg,但还没有使用的项。若 // �ҵ����¾��ֵarg���������ļ�������û�п�������س����벢�˳��� // 找到的新句柄值arg大于最多打开文件数(即没有空闲项),则返回出错码并退出。 24
while (arg < NR_OPEN) 30
return -EMFILE; // ��������ҵ��Ŀ�������������ִ��ʱ�رձ�־λͼclose_on_exec�и�λ�þ��λ�� // 否则针对找到的空闲项(句柄),在执行时关闭标志位图close_on_exec中复位该句柄位。 // ��������exec()�ຯ��ʱ������ر���dup()�����ľ����������ļ��ṹָ�����ԭ�� // 即在运行exec()类函数时,不会关闭用dup()创建的句柄。并令该文件结构指针等于原句 // ��fd��ָ�룬���ҽ��ļ����ü�����1������µ��ļ����arg�� // 柄fd的指针,并且将文件引用计数增1。最后返回新的文件句柄arg。 31
current->close_on_exec &=
@@ -1965,16 +1965,16 @@ return arg; 35 //// �����ļ����ϵͳ���á� //// 复制文件句柄系统调用。 // ����ָ���ļ����oldfd�����ļ����ֵ����newfd�����newfd�Ѵ������ȹر�֮�� // 复制指定文件句柄oldfd,新文件句柄值等于newfd。如果newfd已打开,则首先关闭之。 // ������oldfd
--- ԭ�ļ������newfd - ���ļ������ // 参数:oldfd
+-- 原文件句柄;newfd - 新文件句柄。 // �������ļ����ֵ�� // 返回新文件句柄值。 36 int
sys_dup2(unsigned int oldfd, unsigned
@@ -1984,25 +1984,25 @@ int newfd) 38
sys_close(newfd);
-// �����newfd�Ѿ��������ȹر�֮�� 39
return dupfd(oldfd,newfd);
-// ���Ʋ������¾���� 40 } 41 //// �����ļ����ϵͳ���á� //// 复制文件句柄系统调用。 // ����ָ���ļ����oldfd���¾����ֵ�ǵ�ǰ��С��δ�þ��ֵ�� // 复制指定文件句柄oldfd,新句柄的值是当前最小的未用句柄值。 // ������fildes
--- �����Ƶ��ļ������ // 参数:fildes
+-- 被复制的文件句柄。 // �������ļ����ֵ�� // 返回新文件句柄值。 42 int
sys_dup(unsigned int fildes) 46 //// �ļ�����ϵͳ���ú����� //// 文件控制系统调用函数。 // ����fd���ļ������cmd�ǿ�������μ�include/fcntl.h��23-30�У���arg����Բ� // 参数fd是文件句柄;cmd是控制命令(参见include/fcntl.h,23-30行);arg则针对不 // ͬ�������в�ͬ�ĺ��塣���ڸ��ƾ������F_DUPFD��arg�����ļ������ȡ����Сֵ���� // 同的命令有不同的含义。对于复制句柄命令F_DUPFD,arg是新文件句柄可取的最小值;对 // �������ļ������ͷ��ʱ�־����F_SETFL��arg���µ��ļ������ͷ���ģʽ�������ļ����� // 于设置文件操作和访问标志命令F_SETFL,arg是新的文件操作和访问模式。对于文件上锁 // ����F_GETLK��F_SETLK��F_SETLKW��arg��ָ��flock�ṹ��ָ�롣�����ں���û��ʵ�� // 命令F_GETLK、F_SETLK和F_SETLKW,arg是指向flock结构的指针。但本内核中没有实现 // �ļ��������ܡ� // 文件上锁功能。 // ���أ��������������в���������-1�����ɹ�����ôF_DUPFD �������ļ������ // 返回:若出错,则所有操作都返回-1。若成功,那么F_DUPFD 返回新文件句柄; F_GETFD // �����ļ�����ĵ�ǰִ��ʱ�رձ�־close_on_exec��F_GETFL�����ļ������ͷ��ʱ�־�� // 返回文件句柄的当前执行时关闭标志close_on_exec;F_GETFL返回文件操作和访问标志。 47 int
sys_fcntl(unsigned int fd, unsigned int
@@ -2053,13 +2053,13 @@ struct file * filp; 50 // ���ȼ��������ļ��������Ч�ԡ�Ȼ����ݲ�ͬ����cmd ���зֱ����� ����ļ���� // 首先检查给出的文件句柄的有效性。然后根据不同命令cmd 进行分别处理。 如果文件句柄 // ֵ����һ�����������ļ���NR_OPEN�����߸þ�����ļ��ṹָ��Ϊ�գ��س����� // 值大于一个进程最多打开文件数NR_OPEN,或者该句柄的文件结构指针为空,则返回出错码 // ���˳��� // 并退出。 51
if (fd >= NR_OPEN || !(filp = 54
case F_DUPFD:
-// ���������� 55
return dupfd(fd,arg); 56
case F_GETFD:
-// ȡ�ļ������ִ��ʱ�رձ�־�� 57
return (current->close_on_exec>>fd)&1; 58
-case F_SETFD: // ����ִ��ʱ�رձ�־��argλ0��λ�����ã�����رա� 59
if (arg&1) 64
case F_GETFL:
-// ȡ�ļ�״̬��־�ͷ���ģʽ�� 65
return filp->f_flags; 66
-case F_SETFL: // �����ļ�״̬�ͷ���ģʽ������arg�������ӡ���������־���� 67
filp->f_flags &= ~(O_APPEND | 70
case F_GETLK: case F_SETLK: case F_SETLKW: // δʵ�֡� 71
return -1; 6 7
-#include <string.h> // �ַ���ͷ�ļ�����Ҫ������һЩ�й��ַ���������Ƕ�뺯���� 8
-#include <errno.h> // �����ͷ�ļ�������ϵͳ�и��ֳ����š� 9
-#include <sys/stat.h> // �ļ�״̬ͷ�ļ��������ļ�״̬�ṹstat{}�ͳ����� 10 11
-#include <linux/sched.h> // ���ȳ���ͷ�ļ�������������ṹtask_struct������0���ݵȡ� 12 13
extern int tty_ioctl(int dev, int cmd,
-int arg); // chr_drv/tty_ioctl.c����133�� 14
extern int pipe_ioctl(struct m_inode *pino, int cmd, int arg); //
-fs/pipe.c����118�С� 15 // ���������������(ioctl)����ָ�����͡� // 定义输入输出控制(ioctl)函数指针类型。 16
typedef int (*ioctl_ptr)(int dev,int
@@ -1885,7 +1885,7 @@ cmd,int arg); 17 // ȡϵͳ���豸�����ĺꡣ // 取系统中设备种数的宏。 18
#define NRDEVS ((sizeof (ioctl_ptr))) 19 // ioctl��������ָ����� // ioctl操作函数指针表。 20
static ioctl_ptr ioctl_table[]={ 30 //// ϵͳ���ú��� - ����������ƺ����� //// 系统调用函数 - 输入输出控制函数。 // �ú��������жϲ����������ļ��������Ƿ���Ч��Ȼ����ݶ�Ӧi�ڵ����ļ������ж��ļ� // 该函数首先判断参数给出的文件描述符是否有效。然后根据对应i节点中文件属性判断文件 // ���ͣ������ݾ����ļ����͵�����صĴ��������� // 类型,并根据具体文件类型调用相关的处理函数。 // ������fd
-- �ļ���������cmd - �����룻arg - ������ // 参数:fd
+- 文件描述符;cmd - 命令码;arg - 参数。 // ���أ��ɹ���0�����س����롣 // 返回:成功则返回0,否则返回出错码。 31 int
sys_ioctl(unsigned int fd, unsigned int
@@ -1966,9 +1966,9 @@ int dev,mode; 35 // �����жϸ������ļ�����������Ч�ԡ�����ļ������������ɴ��ļ��������߶�Ӧ���� // 首先判断给出的文件描述符的有效性。如果文件描述符超出可打开的文件数,或者对应描述 // �����ļ��ṹָ��Ϊ�գ��س������˳��� // 符的文件结构指针为空,则返回出错码退出。 36
if (fd >= NR_OPEN || !(filp = current->filp[fd])) 37
return -EBADF; // ����ļ��ṹ��Ӧ���ǹܵ�i�ڵ㣬����ݽ����Ƿ���Ȩ�����ùܵ�ȷ���Ƿ�ִ�йܵ�IO // 如果文件结构对应的是管道i节点,则根据进程是否有权操作该管道确定是否执行管道IO // ���Ʋ���������Ȩִ�������pipe_ioctl()��������Ч�ļ������롣 // 控制操作。若有权执行则调用pipe_ioctl(),否则返回无效文件错误码。 38
if (filp->f_inode->i_pipe) // �������������ļ���ȡ��Ӧ�ļ������ԣ����ݴ��ж��ļ������͡�������ļ��Ȳ����ַ��� // 对于其他类型文件,取对应文件的属性,并据此判断文件的类型。如果该文件既不是字符设 // ���ļ���Ҳ���ǿ��豸�ļ����س������˳��������ַ�����豸�ļ�������ļ���i�� // 备文件,也不是块设备文件,则返回出错码退出。若是字符或块设备文件,则从文件的i节 // ����ȡ�豸�š�����豸�Ŵ���ϵͳ���е��豸�����س����š� // 点中取设备号。如果设备号大于系统现有的设备数,则返回出错号。 40
mode=filp->f_inode->i_mode; 45
return -ENODEV; // Ȼ�����IO���Ʊ�ioctl_table��ö�Ӧ�豸��ioctl����ָ�룬�����øú������������ // 然后根据IO控制表ioctl_table查得对应设备的ioctl函数指针,并调用该函数。如果该设 // ����ioctl����ָ�����û�ж�Ӧ�������س����롣 // 备在ioctl函数指针表中没有对应函数,则返回出错码。 46
if (!ioctl_table[
- ����12-18 linux/fs/select.c 程序12-18 linux/fs/select.c /* * ���ļ����д���select()ϵͳ���õĹ��̡� * 本文件含有处理select()系统调用的过程。 * * ����Peter MacDonald����Mathius Lattner�ṩ��MINIXϵͳ�IJ��� * 这是Peter MacDonald基于Mathius Lattner提供给MINIX系统的补丁 * �����Ķ��ɡ� * 程序修改而成。 */ /* * OK��Peter�����˸��ӵ���ֱ�۵Ķ��_wait()�������Ҷ���Щ���������˸�д����ʹ֮ * OK,Peter编制了复杂但很直观的多个_wait()函数。我对这些函数进行了改写,以使之 * ����ࣺ��Щ������ܲ�����������������Ӧ�ò�����ھ����������⣬���Һ�ʵ�ʡ� * 更简洁:这些代码可能不容易看懂,但是其中应该不会存在竞争条件问题,并且很实际。 * �����������������ƵĴ��룬��ô��˵�����Ѿ�����Linux��˯��/���ѵĹ������ơ� * 如果你能理解这里编制的代码,那么就说明你已经理解Linux中睡眠/唤醒的工作机制。 * * �����ܼĹ��̣�add_wait()��free_wait()ִ������Ҫ������������select���� * 两个很简单的过程,add_wait()和free_wait()执行了主要操作。在整个select处理 * ���������Dz��ò���ֹ�жϡ��������������������̫�����ʧ����Ϊ�����Dz���ִ�� * 过程中我们不得不禁止中断。但是这样做并不会带来太多的损失:因为当我们不在执行 * ������ʱ˯��״̬���Զ����ͷ��жϣ������������ʹ���Լ�EFLAGS�е��жϱ�־���� * 本任务时睡眠状态会自动地释放中断(即其他任务会使用自己EFLAGS中的中断标志)。 */ 46 // ��δ�����������ĵȴ�����ָ�����ȴ���wait_table�С�����*wait_address�������� // 把未准备好描述符的等待队列指针加入等待表wait_table中。参数*wait_address是与描述 // ����صĵȴ�����ͷָ�롣����tty���������secondary�ĵȴ�����ͷָ����proc_list�� // 符相关的等待队列头指针。例如tty读缓冲队列secondary的等待队列头指针是proc_list。 // ���� p��do_select()�ж���ĵȴ����ṹָ�롣 // 参数 p是do_select()中定义的等待表结构指针。 47
static void add_wait(struct 50 // �����ж��������Ƿ��ж�Ӧ�ĵȴ����У������ء�Ȼ���ڵȴ�������������ָ���ĵȴ� // 首先判断描述符是否有对应的等待队列,若无则返回。然后在等待表中搜索参数指定的等待 // ����ָ���Ƿ��Ѿ��ڵȴ��������ù��������ù�Ҳ���̷��ء�����ж���Ҫ����Թܵ��ļ� // 队列指针是否已经在等待表中设置过,若设置过也立刻返回。这个判断主要是针对管道文件 // ��������������һ���ܵ��ڵȴ����Խ��ж���������ô��ض��������̽���д������ // 描述符。例如若一个管道在等待可以进行读操作,那么其必定可以立刻进行写操作。 51
if (!wait_address) 55
return; // Ȼ�����ǰ���������Ӧ�ȴ����е�ͷָ�뱣���ڵȴ���wait_table�У�ͬʱ�õȴ������ // 然后我们把描述符对应等待队列的头指针保存在等待表wait_table中,同时让等待表项的 // old_task�ֶ�ָ��ȴ�����ͷָ��ָ�������������ΪNULL�������õȴ�����ͷָ��ָ // old_task字段指向等待队列头指针指向的任务(若无则为NULL),在让等待队列头指针指 // ��ǰ�������ѵȴ�����Ч�����ֵnr��1�����ڵ�179�б���ʼ��Ϊ0���� // 向当前任务。最后把等待表有效项计数值nr增1(其在第179行被初始化为0)。 56
p->entry[p->nr].wait_address = wait_address; 61 // ��յȴ����������ǵȴ����ṹָ�롣��������do_select()������˯�ߺ��ѷ���ʱ������ // 清空等待表。参数是等待表结构指针。本函数在do_select()函数中睡眠后被唤醒返回时被调用 // ����204��207�У������ڻ��ѵȴ����д��ڸ����ȴ������ϵ�������������kernel/sched.c // (第204、207行),用于唤醒等待表中处于各个等待队列上的其他任务。它与kernel/sched.c // ��sleep_on()�����ĺ�벿�ִ��뼸����ȫ��ͬ����ο���sleep_on()������˵���� // 中sleep_on()函数的后半部分代码几乎完全相同,请参考对sleep_on()函数的说明。 62
static void free_wait(task_struct ** tpp; 66 // ����ȴ����и����nr ����Ч���¼�ĵȴ�����ͷָ��������������������ӽ��ĵȴ� // 如果等待表中各项(供nr 个有效项)记录的等待队列头指针表明还有其他后来添加进的等待 // ���������������̵��� sleep_on() ������˯���ڸõȴ������ϣ������ʱ�ȴ�����ͷָ�� // 任务(例如其他进程调用 sleep_on() 函数而睡眠在该等待队列上),则此时等待队列头指针 // ָ��IJ��ǵ�ǰ���̣���ô���Ǿ���Ҫ�Ȼ�����Щ�����������ǽ��ȴ�����ͷ��ָ������ // 指向的不是当前进程,那么我们就需要先唤醒这些任务。操作方法是将等待队列头所指任务先 // ��Ϊ����״̬��state = 0���������Լ�����Ϊ�����жϵȴ�״̬�����Լ�Ҫ�ȴ���Щ�������� // 置为就绪状态(state = 0),并把自己设置为不可中断等待状态,即自己要等待这些后续进队 // �е������Ѷ�ִ��ʱ�����ѱ�����Ȼ������ִ�е��ȳ��� // 列的任务被唤醒而执行时来唤醒本任务。然后重新执行调度程序。 67
for (i = 0; i < p->nr ; i++) { 73
} // ִ�е����˵���ȴ�����ǰ�������еĵȴ�����ͷָ���ֶ�wait_addressָ��ǰ���� // 执行到这里,说明等待表当前处理项中的等待队列头指针字段wait_address指向当前任务, // ����Ϊ�գ���������������⣬������ʾ������Ϣ��Ȼ�������õȴ�����ͷָ��ָ�������� // 若它为空,则表明调度有问题,于是显示警告信息。然后我们让等待队列头指针指向在我们 // ǰ�������е�����76�У�������ʱ��ͷָ��ȷʵָ��һ�����������NULL����˵�� // 前面进入队列的任务(第76行)。若此时该头指针确实指向一个任务而不是NULL,则说明 // �����л�������*tpp��Ϊ�գ������ǽ����������óɾ���״̬������֮�����ѵȴ����� // 队列中还有任务(*tpp不为空),于是将该任务设置成就绪状态,唤醒之。最后把等待表的 // ��Ч��������ֶ�nr���㡣 // 有效表项计数字段nr清零。 74
if (!*tpp) 81 // �����ļ�i�ڵ��ж��ļ��Ƿ����ַ��ն��豸�ļ�����������tty�ṹָ�룬����NULL�� // 根据文件i节点判断文件是否是字符终端设备文件。若是则返回其tty结构指针,否则返回NULL。 82
static struct tty_struct * 85 // ��������ַ��豸�ļ���NULL��������豸�Ų���5�������նˣ���4����NULL�� // 如果不是字符设备文件则返回NULL。如果主设备号不是5(控制终端)或4,则返回NULL。 86
if (!S_ISCHR(inode->i_mode)) 89
return NULL; // ������豸����5����ô���ն��豸�ŵ��ڽ��̵�tty�ֶ�ֵ������͵����ַ��豸�ļ����豸�š� // 如果主设备号是5,那么其终端设备号等于进程的tty字段值,否则就等于字符设备文件次设备号。 // ����ն��豸��С��0����ʾ����û�п����ն˻�û��ʹ���նˣ����Ƿ���NULL�����ض�Ӧ�� // 如果终端设备号小于0,表示进程没有控制终端或没有使用终端,于是返回NULL。否则返回对应的 // tty�ṹָ�롣 // tty结构指针。 90
if (major == 5) /* * check_XX�������ڼ��һ���ļ�������֪�����ļ�Ҫô�ǹܵ��ļ��� * check_XX函数用于检查一个文件。我们知道该文件要么是管道文件、 * Ҫô���ַ��豸�ļ�������Ҫô��һ��FIFO��FIFO��δʵ�֣��� * 要么是字符设备文件,或者要么是一个FIFO(FIFO还未实现)。 */ // �����ļ������Ƿ����ã����ն˶��������secondary�Ƿ����ַ��ɶ������߹ܵ��ļ��Ƿ� // 检查读文件操作是否准备好,即终端读缓冲队列secondary是否有字符可读,或者管道文件是否 // ���ա�����wait�ǵȴ���ָ�룻inode���ļ�i�ڵ�ָ�롣���������ɽ��ж�������1���� // 不空。参数wait是等待表指针;inode是文件i节点指针。若描述符可进行读操作则返回1,否 // ��0�� // 则返回0。 103 static int check_in(tty_struct * tty; 106 // ���ȸ����ļ�i�ڵ����get_tty()����ļ��Ƿ���һ��tty�նˣ��ַ����豸�ļ���������� // 首先根据文件i节点调用get_tty()检测文件是否是一个tty终端(字符)设备文件,如果是则 // �����ն˶��������secondary���Ƿ����ַ��ɹ���ȡ��������1������ʱsecondaryΪ // 检查该终端读缓冲队列secondary中是否有字符可供读取,若有则返回1,若此时secondary为 // ����ѵ�ǰ�������ӵ�secondary�ĵȴ�����proc_list�ϲ�����0������ǹܵ��ļ������ж� // 空则把当前任务添加到secondary的等待队列proc_list上并返回0。如果是管道文件,则判断 // Ŀǰ�ܵ����Ƿ����ַ��ɶ���������1����û�У��ܵ��գ���ѵ�ǰ�������ӵ��ܵ�i�ڵ� // 目前管道中是否有字符可读,若有则返回1,若没有(管道空)则把当前任务添加到管道i节点 // �ĵȴ������ϲ�����0��ע�⣬PIPE_EMPTY()��ʹ�ùܵ���ǰͷβָ��λ�����жϹܵ��Ƿ�ա� // 的等待队列上并返回0。注意,PIPE_EMPTY()宏使用管道当前头尾指针位置来判断管道是否空。 // �ܵ�i�ڵ��i_zone[0]��i_zone[1]�ֶηֱ����Źܵ���ǰ��ͷβָ�롣 // 管道i节点的i_zone[0]和i_zone[1]字段分别存放着管道当前的头尾指针。 107 if (tty = } 119 // ����ļ�д�����Ƿ����ã����ն�д�������write_q���Ƿ��п���λ�ÿ�д�����ߴ�ʱ�� // 检查文件写操作是否准备好,即终端写缓冲队列write_q中是否还有空闲位置可写,或者此时管 // ���ļ��Ƿ���������wait�ǵȴ���ָ�룻inode���ļ�i�ڵ�ָ�롣���������ɽ���д������ // 道文件是否不满。参数wait是等待表指针;inode是文件i节点指针。若描述符可进行写操作则 // ����1������0�� // 返回1,否则返回0。 120 static int check_out(tty_struct * tty; 123 // ���ȸ����ļ�i�ڵ����get_tty()����ļ��Ƿ���һ��tty�նˣ��ַ����豸�ļ���������� // 首先根据文件i节点调用get_tty()检测文件是否是一个tty终端(字符)设备文件,如果是则 // �����ն�д�������write_q���Ƿ��пռ��д�룬������1����û�пտռ���ѵ�ǰ�� // 检查该终端写缓冲队列write_q中是否有空间可写入,若有则返回1,若没有空空间则把当前任 // �����ӵ�write_q�ĵȴ�����proc_list�ϲ�����0������ǹܵ��ļ����ж�Ŀǰ�ܵ����Ƿ��� // 务添加到write_q的等待队列proc_list上并返回0。如果是管道文件则判断目前管道中是否有 // ���пռ��д���ַ���������1����û�У��ܵ�������ѵ�ǰ�������ӵ��ܵ�i�ڵ�ĵȴ� // 空闲空间可写入字符,若有则返回1,若没有(管道满)则把当前任务添加到管道i节点的等待 // �����ϲ�����0�� // 队列上并返回0。 124 if (tty = } 136 // ����ļ��Ƿ����쳣״̬�������ն��豸�ļ���Ŀǰ�ں����Ƿ���0�����ڹܵ��ļ������ // 检查文件是否处于异常状态。对于终端设备文件,目前内核总是返回0。对于管道文件,如果 // ��ʱ�����ܵ�����������һ�����ѱ��رգ���1������Ͱѵ�ǰ�������ӵ��ܵ�i�ڵ� // 此时两个管道描述符中有一个或都已被关闭,则返回1,否则就把当前任务添加到管道i节点 // �ĵȴ������ϲ�����0������0������wait�ǵȴ���ָ�룻inode���ļ�i�ڵ�ָ�롣������ // 的等待队列上并返回0。返回0。参数wait是等待表指针;inode是文件i节点指针。若出现 // �쳣������1������0�� // 异常条件则返回1,否则返回0。 137 static int check_ex( } 153 // do_select() ���ں�ִ��select()ϵͳ���õ�ʵ�ʴ����������ú������ȼ�����������и��� // do_select() 是内核执行select()系统调用的实际处理函数。该函数首先检查描述符集中各个 // ����������Ч�ԣ�Ȼ��ֱ�����������������������麯��check_XX()��ÿ�����������м� // 描述符的有效性,然后分别调用相关描述符集描述符检查函数check_XX()对每个描述符进行检 // �飬ͬʱͳ�����������е�ǰ�Ѿ����õ������������������κ�һ���������Ѿ����ã��� // 查,同时统计描述符集中当前已经准备好的描述符个数。若有任何一个描述符已经准备好,本 // �����ͻ����̷��أ�������̾ͻ��ڱ������н���˯��״̬�����ڹ��˳�ʱʱ���������ij�� // 函数就会立刻返回,否则进程就会在本函数中进入睡眠状态,并在过了超时时间或者由于某个 // ���������ڵȴ������ϵĽ��̱����Ѷ�ʹ�����̼������С� // 描述符所在等待队列上的进程被唤醒而使本进程继续运行。 154 int do_select( { 158 select_table wait_table;
-// �ȴ����ṹ�� 159 int i; 161 // ���Ȱ�3�������������л��������mask�еõ�������������Ч����������λ�����롣 Ȼ�� // 首先把3个描述符集进行或操作,在mask中得到描述符集中有效描述符比特位屏蔽码。 然后 // ѭ���жϵ�ǰ���̸����������Ƿ���Ч���Ұ��������������ڡ���ѭ���У�ÿ�ж���һ������ // 循环判断当前进程各个描述符是否有效并且包含在描述符集内。在循环中,每判断完一个描述 // ���ͻ��mask����1λ����˸���mask�������Ч����λ���ǾͿ����ж���Ӧ�������Ƿ��� // 符就会把mask右移1位,因此根据mask的最低有效比特位我们就可以判断相应描述符是否在 // �û����������������С���Ч��������Ӧ����һ���ܵ��ļ���������������һ���ַ��豸�ļ� // 用户给定的描述符集中。有效的描述符应该是一个管道文件描述符,或者是一个字符设备文件 // ��������������һ��FIFO���������������͵Ķ���Ϊ��Ч������������EBADF���� // 描述符,或者是一个FIFO描述符,其余类型的都作为无效描述符而返回EBADF错误。 162 mask = in | out |
@@ -2589,7 +2589,7 @@ lang=EN-US> for (i = 0 ; i <
164
if (!(mask & 1))
-// ����������������������ж���һ���� 165
@@ -2598,7 +2598,7 @@ continue; 166
if (!current->filp[i])
-// �����ļ�δ�������������� 167
@@ -2607,7 +2607,7 @@ return -EBADF; 168
if (!current->filp[i]->f_inode)
-// ���ļ�i�ڵ�ָ��գ��ش���š� 169
@@ -2616,7 +2616,7 @@ return -EBADF; 170
if (current->filp[i]->f_inode->i_pipe)
-// ���ǹܵ��ļ�������������Ч�� 171
@@ -2625,7 +2625,7 @@ continue; 172
if (S_ISCHR(current->filp[i]->f_inode->i_mode))
-// �ַ��豸�ļ���Ч�� 173
@@ -2634,7 +2634,7 @@ continue; 174 if
(S_ISFIFO(current->filp[i]->f_inode->i_mode))
-// FIFOҲ��Ч�� 175
@@ -2643,26 +2643,26 @@ continue; 176
return -EBADF;
-// �����Ϊ��Ч�����������ء� 177 } // ���濪ʼѭ�����3�����������еĸ����������Ƿ����ã����Բ���������ʱmask������ǰ // 下面开始循环检查3个描述符集中的各个描述符是否准备好(可以操作)。此时mask用作当前 // ���ڴ����������������롣ѭ���е�3������check_in()��check_out()��check_ex()�ֱ��� // 正在处理描述符的屏蔽码。循环中的3个函数check_in()、check_out()和check_ex()分别用 // ���ж��������Ƿ��Ѿ����á���һ���������Ѿ����ã���������������������ö�Ӧ���� // 来判断描述符是否已经准备好。若一个描述符已经准备好,则在相关描述符集中设置对应比特 // λ�����Ұ���������������������ֵcount��1����183��forѭ������е� mask += mask // 位,并且把已准备好描述符个数计数值count增1。第183行for循环语句中的 mask += mask // ��Ч�� mask<<
-1�� // 等效于 mask<<
+1。 178 repeat: // �����ʱ�жϵ��������ڶ��������������У����Ҹ��������Ѿ����ÿ��Խ��ж���������� // 如果此时判断的描述符在读操作描述符集中,并且该描述符已经准备好可以进行读操作,则把 // ������������������in�ж�Ӧ����λ��Ϊ1��ͬʱ����������������������ֵcount��1�� // 该描述符在描述符集in中对应比特位置为1,同时把已准备好描述符个数计数值count增1。 184
@@ -2703,22 +2703,22 @@ style='color:blue'>current->filp[i]->f_inode)) { 186
*inp |= mask;
-// �������������ö�Ӧ����λ�� 187
count++;
-// ���������������������� 188
} // �����ʱ�жϵ���������д�������������У����Ҹ��������Ѿ����ÿ��Խ���д��������� // 如果此时判断的描述符在写操作描述符集中,并且该描述符已经准备好可以进行写操作,则把 // ������������������out�ж�Ӧ����λ��Ϊ1��ͬʱ����������������������ֵcount��1�� // 该描述符在描述符集out中对应比特位置为1,同时把已准备好描述符个数计数值count增1。 189
@@ -2741,11 +2741,11 @@ lang=EN-US> &nb
lang=EN-US>
} // �����ʱ�жϵ����������쳣���������У����Ҹ��������Ѿ����쳣���֣���Ѹ����������� // 如果此时判断的描述符在异常描述符集中,并且该描述符已经有异常出现,则把该描述符在描 // ������ex�ж�Ӧ����λ��Ϊ1��ͬʱ����������������������ֵcount��1�� // 述符集ex中对应比特位置为1,同时把已准备好描述符个数计数值count增1。 194
@@ -2771,18 +2771,18 @@ lang=EN-US> &nb
199 } // �ڶԽ��������������жϴ���������û�з����������õ���������count==0�������Ҵ�ʱ // 在对进程所有描述符判断处理过后,若没有发现有已准备好的描述符(count==0),并且此时 // ����û���յ��κη������źţ����Ҵ�ʱ�еȴ��ŵ����������ߵȴ�ʱ�仹û�г�ʱ����ô�� // 进程没有收到任何非阻塞信号,并且此时有等待着的描述符或者等待时间还没有超时,那么我 // �ǾͰѵ�ǰ����״̬���óɿ��ж�˯��״̬��Ȼ��ִ�е��Ⱥ���ȥִ�����������ں���һ // 们就把当前进程状态设置成可中断睡眠状态,然后执行调度函数去执行其他任务。当内核又一 // �ε���ִ�б�����ʱ�͵���free_wait()������صȴ������ϱ�����ǰ�������Ȼ����ת�� // 次调度执行本任务时就调用free_wait()唤醒相关等待队列上本任务前后的任务,然后跳转到 // repeat��Ŵ���178�У��ٴ����¼���Ƿ������ǹ��ĵģ����������еģ������������á� // repeat标号处(178行)再次重新检测是否有我们关心的(描述符集中的)描述符已准备好。 200 if (!( &nb
204
free_wait(&wait_table);
-// �������ѷ��غ�����↑ʼִ�С� 205
@@ -2815,11 +2815,11 @@ goto repeat; 206 } // �����ʱcount������0�����߽��յ����źţ����ߵȴ�ʱ�䵽����û����Ҫ�ȴ����������� // 如果此时count不等于0,或者接收到了信号,或者等待时间到并且没有需要等待的描述符, // ��ô���Ǿ͵���free_wait()���ѵȴ������ϵ�����Ȼ�������õ�����������ֵ�� // 那么我们就调用free_wait()唤醒等待队列上的任务,然后返回已准备好的描述符个数值。 207 */ /* * ע�����Dz��ܷ���-ERESTARTSYS����Ϊ���ǻ���select���й����иı� * 注意我们不能返回-ERESTARTSYS,因为我们会在select运行过程中改变 * �������ֵ��*timeout�����ܲ��ң�����Ҳֻ�ܽ��������ʵ���������� * 输入参数值(*timeout)。很不幸,但你也只能接受这个事实。不过我们 * �����ڿ⺯������Щ���� * 可以在库函数中做些处理... */ // selectϵͳ���ú������ú����еĴ�����Ҫ�������select���ܲ���ǰ��IJ������ƺ�ת�� // select系统调用函数。该函数中的代码主要负责进行select功能操作前后的参数复制和转换 // ������select��Ҫ�Ĺ�����do_select()��������ɡ�sys_select()�����ȸ��ݲ����������� // 工作。select主要的工作由do_select()函数来完成。sys_select()会首先根据参数传递来的 // ������ָ����û����ݿռ�� select() �������õIJ����ֽ⸴�Ƶ��ں˿ռ䣬Ȼ��������Ҫ // 缓冲区指针从用户数据空间把 select() 函数调用的参数分解复制到内核空间,然后设置需要 // �ȴ��ij�ʱʱ��ֵtimeout�����ŵ���do_select() ִ�� select���ܣ����غ�ͰѴ������ // 等待的超时时间值timeout,接着调用do_select() 执行 select功能,返回后就把处理结果 // �ٸ��ƻ��û��ռ��С� // 再复制会用户空间中。 // ����bufferָ���û���������select()�����ĵ�1�����������������ֵС��0��ʾִ��ʱ // 参数buffer指向用户数据区中select()函数的第1个参数处。如果返回值小于0表示执行时 // ���ִ����������ֵ����0�����ʾ�ڹ涨�ȴ�ʱ����û�����������ò������������ֵ // 出现错误;如果返回值等于0,则表示在规定等待时间内没有描述符准备好操作;如果返回值 // ����0�����ʾ�����õ������������� // 大于0,则表示已准备好的描述符数量。 216 int sys_select( unsigned
@@ -2899,11 +2899,11 @@ lang=EN-US> { 218 /* Perform the select(nd, in, out, ex, tv) system call. */ /* ִ��select(nd,
-in, out, ex, tv)ϵͳ���� */ /* 执行select(nd,
+in, out, ex, tv)系统调用 */ // ���ȶ��弸���ֲ����������ڰ�ָ�������������select()���������ֽ���� // 首先定义几个局部变量,用于把指针参数传递来的select()函数参数分解开来。 219 int i; 220 fd_set res_in, in = 0, *inp;
-// ���������������� 221 fd_set res_out, out = 0, *outp;
-// ������������� 222 fd_set res_ex, ex = 0, *exp;
-// �쳣�������������� 223 fd_set mask;
-// ��������������ֵ��Χ��nd�������롣 224 struct timeval *tvp;
-// �ȴ�ʱ��ṹָ�롣 225 unsigned long
@@ -2940,18 +2940,18 @@ timeout; 226 // Ȼ����û��������Ѳ����ֱ���븴�Ƶ��ֲ�ָ������У���������������ָ���Ƿ���Ч�ֱ� // 然后从用户数据区把参数分别隔离复制到局部指针变量中,并根据描述符集指针是否有效分别 // ȡ��3����������in��������out��д����ex���쳣��������
-mask Ҳ��һ���������������� // 取得3个描述符集in(读)、out(写)和ex(异常)。其中
+mask 也是一个描述符集变量, // ����3�����������������������ֵ+1������1������nd��ֵ�����������ó��û�������ĵ� // 根据3个描述符集中最大描述符数值+1(即第1个参数nd的值),它被设置成用户程序关心的 // �����������������롣���磬��nd = 4����mask = 0b00001111����32���أ��� // 所有描述符的屏蔽码。例如,若nd = 4,则mask = 0b00001111(共32比特)。 227 mask = ~((~0)
@@ -2978,7 +2978,7 @@ lang=EN-US> 233 if (inp)
-// ��ָ����Ч����ȡ���������������� 234
@@ -2986,7 +2986,7 @@ in = mask & get_fs_long(inp);<
235 if (outp)
-// ��ָ����Ч����ȡд�������������� 236
@@ -2994,26 +2994,26 @@ out = mask & get_fs_long(outp);237 if (exp)
-// ��ָ����Ч����ȡ�쳣���������� 238
ex = mask & get_fs_long(exp); // ���������dz��Դ�ʱ��ṹ��ȡ���ȴ���˯�ߣ�ʱ��ֵtimeout�����Ȱ�timeout��ʼ������� // 接下来我们尝试从时间结构中取出等待(睡眠)时间值timeout。首先把timeout初始化成最大 // �����ޣ�ֵ��Ȼ����û����ݿռ�ȡ�ø�ʱ��ṹ�����õ�ʱ��ֵ����ת���ͼ���ϵͳ��ǰ�δ� // (无限)值,然后从用户数据空间取得该时间结构中设置的时间值,经转换和加上系统当前滴答 // ֵjiffies�����õ���Ҫ�ȴ���ʱ��δ���ֵ
-timeout�������ô�ֵ�����õ�ǰ����Ӧ�õȴ� // 值jiffies,最后得到需要等待的时间滴答数值
+timeout。我们用此值来设置当前进程应该等待 // ����ʱ�����⣬��241����tv_usec�ֶ�����ֵ����������1000000��ɵõ���Ӧ�������ٳ� // 的延时。另外,第241行上tv_usec字段是微秒值,把它除以1000000后可得到对应秒数,再乘 // ��ϵͳÿ��δ���HZ������tv_usecת���ɵδ�ֵ�� // 以系统每秒滴答数HZ,即把tv_usec转换成滴答值。 239 timeout =
@@ -3042,31 +3042,31 @@ lang=EN-US> } 245 current->timeout = timeout;
- // ���õ�ǰ����Ӧ����ʱ�ĵδ�ֵ�� // select()��������Ҫ������do_select()����ɡ��ڵ��øú���֮��Ĵ������ڰѴ���������� // select()函数的主要工作在do_select()中完成。在调用该函数之后的代码用于把处理结果复制 // ���û��������У����ظ��û���Ϊ�˱�����־����������ڵ���do_select()ǰ��Ҫ��ֹ�жϣ� // 到用户数据区中,返回给用户。为了避免出现竞争条件,在调用do_select()前需要禁止中断, // ���ڸú������غ��ٿ����жϡ� // 并在该函数返回后再开启中断。 // �����do_select()����֮����̵ĵȴ���ʱ�ֶ�timeout�����ڵ�ǰϵͳ��ʱ�δ�ֵjiffies�� // 如果在do_select()返回之后进程的等待延时字段timeout还大于当前系统计时滴答值jiffies, // ˵���ڳ�ʱ֮ǰ�Ѿ������������ã��������������ȼ��µ���ʱ��ʣ���ʱ��ֵ��������ǻ� // 说明在超时之前已经有描述符准备好,于是这里我们先记下到超时还剩余的时间值,随后我们会 // �����ֵ���ظ��û���������̵ĵȴ���ʱ�ֶ�timeout�Ѿ�С�ڻ���ڵ�ǰϵͳjiffies���� // 把这个值返回给用户。如果进程的等待延时字段timeout已经小于或等于当前系统jiffies,表 // ʾdo_select()���������ڳ�ʱ�����أ���˰�ʣ��ʱ��ֵ����Ϊ0�� // 示do_select()可能是由于超时而返回,因此把剩余时间值设置为0。 246 cli();
-// ��ֹ��Ӧ�жϡ� 247 i = 252 sti();
-// �����ж���Ӧ�� // ���������ǰѽ��̵ij�ʱ�ֶ����㡣���do_select()���ص�����������������С��0����ʾ // 接下来我们把进程的超时字段清零。如果do_select()返回的已准备好描述符个数小于0,表示 // ִ�г��������Ƿ����������š�Ȼ�����ǰѴ������������������ݺ��ӳ�ʱ��ṹ����д�ص� // 执行出错,于是返回这个错误号。然后我们把处理过的描述符集内容和延迟时间结构内容写回到 // �û����ݻ���ռ䡣��дʱ��ṹ����ʱ����Ҫ�Ƚ��δ�ʱ�䵥λ��ʾ��ʣ���ӳ�ʱ��ת������ // 用户数据缓冲空间。在写时间结构内容时还需要先将滴答时间单位表示的剩余延迟时间转换成秒 // ����ֵ�� // 和微秒值。 253 &nb
258
put_fs_long(res_in,inp);
-// �ɶ����������� 259 } 262
put_fs_long(res_out,outp);
-// ����������� 263 } 266
put_fs_long(res_ex,exp);
-// �����쳣�������������� 267 } 271
@@ -3184,14 +3184,14 @@ timeout *= (1000000/HZ); 273
put_fs_long(timeout, (unsigned long *)
-&tvp->tv_usec); // �롣 274 } // �����ʱ��û�������õ��������������յ���ij���������źţ��ر��жϴ���š� // 如果此时并没有已准备好的描述符,并且收到了某个非阻塞信号,则返回被中断错误号。 // ���������õ�����������ֵ�� // 否则返回已准备好的描述符个数值。 275 if (!i && (
- ���� 程序 12-2 linux/fs/bitmap.c 7 /*
bitmap.c contains the code that handles the inode and block bitmaps */ /* bitmap.c�����д���i�ڵ�ʹ��̿�λͼ�Ĵ��� */ /* bitmap.c程序含有处理i节点和磁盘块位图的代码 */ 8
-#include <string.h> // �ַ���ͷ�ļ�����Ҫ������һЩ�й��ַ���������Ƕ�뺯���� 9 //
-����ʹ�������е�memset()������ 10
-#include <linux/sched.h> // ���ȳ���ͷ�ļ�����������ṹtask_struct������0���ݡ� 11
-#include <linux/kernel.h> // �ں�ͷ�ļ�������һЩ�ں˳��ú�����ԭ�ζ��塣 12 //// ��ָ����ַ��addr������һ��1024�ֽ��ڴ����㡣 //// 将指定地址(addr)处的一块1024字节内存清零。 // ���룺eax
-= 0��ecx = �Գ���Ϊ��λ�����ݿ鳤�ȣ�BLOCK_SIZE/4����edi = ָ����ʼ�� // 输入:eax
+= 0;ecx = 以长字为单位的数据块长度(BLOCK_SIZE/4);edi = 指定起始地 // ַaddr�� // 址addr。 13
#define clear_block(addr) \ 14
__asm__("cld\n\t" \
-// �巽��λ�� 15
"rep\n\t" \
-// �ظ�ִ�д洢���ݣ�0���� 16
"stosl" \ 18 //// ��ָ����ַ��ʼ�ĵ�nr��λƫ�ƴ��ı���λ��λ��nr�ɴ���32����������ԭ����λֵ�� //// 把指定地址开始的第nr个位偏移处的比特位置位(nr可大于32!)。返回原比特位值。 // ���룺%0
--eax������ֵ����%1 -eax(0)��%2 -nr��λƫ��ֵ��%3 -(addr)��addr�����ݡ� // 输入:%0
+-eax(返回值);%1 -eax(0);%2 -nr,位偏移值;%3 -(addr),addr的内容。 // ��20�ж�����һ���ֲ��Ĵ�������res���ñ�������������ָ����eax�Ĵ����У��Ա��� // 第20行定义了一个局部寄存器变量res。该变量将被保存在指定的eax寄存器中,以便于 // ��Ч���ʺͲ��������ֶ�������ķ�����Ҫ������Ƕ�������С���ϸ˵���μ�gcc�ֲ� // 高效访问和操作。这种定义变量的方法主要用于内嵌汇编程序中。详细说明参见gcc手册 // ����ָ���Ĵ����еı������������궨����һ��������ʽ���ñ���ʽֵ�����res��ֵ�� // “在指定寄存器中的变量”。整个宏定义是一个语句表达式,该表达式值是最后res的值。 // ��21���ϵ�btslָ�����ڲ��Բ����ñ���λ��Bit Test and Set�����ѻ���ַ��%3���� // 第21行上的btsl指令用于测试并设置比特位(Bit Test and Set)。把基地址(%3)和 // ����λƫ��ֵ��%2����ָ���ı���λֵ�ȱ��浽��λ��־CF�У�Ȼ�����øñ���λΪ1�� // 比特位偏移值(%2)所指定的比特位值先保存到进位标志CF中,然后设置该比特位为1。 // ָ��setb���ڸ��ݽ�λ��־CF���ò�������%al�������CF=1��%al =1������%al =0�� // 指令setb用于根据进位标志CF设置操作数(%al)。如果CF=1则%al =1,否则%al =0。 19
#define set_bit(nr,addr) ({\ 24 //// ��λָ����ַ��ʼ�ĵ�nrλƫ�ƴ��ı���λ������ԭ����λֵ�ķ��롣 //// 复位指定地址开始的第nr位偏移处的比特位。返回原比特位值的反码。 // ���룺%0
--eax������ֵ����%1 -eax(0)��%2 -nr��λƫ��ֵ��%3 -(addr)��addr�����ݡ� // 输入:%0
+-eax(返回值);%1 -eax(0);%2 -nr,位偏移值;%3 -(addr),addr的内容。 // ��27���ϵ�btrlָ�����ڲ��Բ���λ����λ��Bit Test and Reset����������������� // 第27行上的btrl指令用于测试并复位比特位(Bit Test and Reset)。其作用与上面的 // btsl���ƣ����Ǹ�λָ������λ��ָ��setnb���ڸ��ݽ�λ��־CF���ò�������%al���� // btsl类似,但是复位指定比特位。指令setnb用于根据进位标志CF设置操作数(%al)。 // ���CF
-= 1��%al = 0������%al = 1�� // 如果CF
+= 1则%al = 0,否则%al = 1。 25
#define clear_bit(nr,addr) ({\ 30 //// ��addr��ʼѰ�ҵ�1��0ֵ����λ�� //// 从addr开始寻找第1个0值比特位。 // ���룺%0
-- ecx(����ֵ)��%1 - ecx(0)��%2 - esi(addr)�� // 输入:%0
+- ecx(返回值);%1 - ecx(0);%2 - esi(addr)。 // ��addrָ����ַ��ʼ��λͼ��Ѱ�ҵ�1����0�ı���λ�����������addr�ı���λƫ�� // 在addr指定地址开始的位图中寻找第1个是0的比特位,并将其距离addr的比特位偏移 // ֵ���ء�addr�ǻ�����������ĵ�ַ��ɨ��Ѱ�ҵķ�Χ��1024�ֽڣ�8192����λ���� // 值返回。addr是缓冲块数据区的地址,扫描寻找的范围是1024字节(8192比特位)。 31
#define find_first_zero(addr) ({ \ 33
__asm__("cld\n" \
-// �巽��λ�� 34
"1:\tlodsl\n\t" \
-// ȡ[esi]��eax�� 35
"notl %%eax\n\t" \
-// eax��ÿλȡ���� 36
-"bsfl %%eax,%%edx\n\t" \ // ��λ0ɨ��eax����1�ĵ�1��λ����ƫ��ֵ��edx�� 37
-"je 2f\n\t" \ // ���eax��ȫ��0������ǰ��ת�����2��(40��)�� 38
-"addl %%edx,%%ecx\n\t" \ // ƫ��ֵ����ecx��ecx��λͼ��0ֵλ��ƫ��ֵ���� 39
-"jmp 3f\n" \ // ��ǰ��ת�����3������������ 40
- "2:\taddl $32,%%ecx\n\t" \ // δ�ҵ�0ֵλ����ecx��1�����ֵ�λƫ����32�� 41
-"cmpl $8192,%%ecx\n\t" \ // �Ѿ�ɨ����8192����λ��1024�ֽڣ����� 42
"jl 1b\n" \
-// ����û��ɨ����1�����ݣ�����ǰ��ת�����1���� 43
"3:" \
-// ��������ʱecx����λƫ������ 44
:"=c" (__res):"c" (0),"S"
@@ -2056,15 +2056,15 @@ __res;}) 46 //// �ͷ��豸dev���������е�����block�� //// 释放设备dev上数据区中的逻辑块block。 // ��λָ������block��Ӧ������λͼ����λ���ɹ���1������0�� // 复位指定逻辑块block对应的逻辑块位图比特位。成功则返回1,否则返回0。 // ������dev���豸�ţ�block������ţ��̿�ţ��� // 参数:dev是设备号,block是逻辑块号(盘块号)。 47 int
free_block(int dev, int block) 51 // ����ȡ�豸dev���ļ�ϵͳ�ij�������Ϣ������������������ʼ����ź��ļ�ϵͳ���� // 首先取设备dev上文件系统的超级块信息,根据其中数据区开始逻辑块号和文件系统中逻辑 // ��������Ϣ�жϲ���block����Ч�ԡ����ָ���豸�����鲻���ڣ������ͣ���������� // 块总数信息判断参数block的有效性。如果指定设备超级块不存在,则出错停机。若逻辑块 // ��С��������������1������Ŀ�Ż��ߴ����豸������������Ҳ����ͣ���� // 号小于盘上数据区第1个逻辑块的块号或者大于设备上总逻辑块数,也出错停机。 52
if (!(sb = get_super(dev)))
- // fs/super.c����56�� 53
panic("trying to free block on
@@ -2106,22 +2106,22 @@ in datazone"); 56
bh = get_hash_table(dev,block); // Ȼ��� hash����Ѱ�Ҹÿ����ݡ����ҵ������ж�����Ч�ԣ��������ĺ��±�־���ͷ� // 然后从 hash表中寻找该块数据。若找到了则判断其有效性,并清已修改和更新标志,释放 // �����ݿ顣�öδ������Ҫ��;�����������Ŀǰ�����ڸ��ٻ������У����ͷŶ�Ӧ�Ļ� // 该数据块。该段代码的主要用途是如果该逻辑块目前存在于高速缓冲区中,就释放对应的缓 // ��顣 // 冲块。 57
if (bh) { 58
-if (bh->b_count > 1) { // �����������1�������brelse()�� 59
brelse(bh); //
-b_count--���˳����ÿ黹�����á� 60
return 0; 62
bh->b_dirt=0; //
-����λ���ĺ��Ѹ��±�־�� 63
bh->b_uptodate=0; 64
if (bh->b_count) //
-����ʱb_countΪ1�������brelse()�ͷ�֮�� 65
brelse(bh); 66
} // �������Ǹ�λblock������λͼ�еı���λ����0�����ȼ���block����������ʼ����� // 接着我们复位block在逻辑块位图中的比特位(置0)。先计算block在数据区开始算起的 // ��������ţ���1��ʼ��������Ȼ�������(����)λͼ���в�������λ��Ӧ�ı���λ�� // 数据逻辑块号(从1开始计数)。然后对逻辑块(区块)位图进行操作,复位对应的比特位。 // �����Ӧ����λԭ������0�������ͣ��������1���������1024�ֽڣ���8192����λ�� // 如果对应比特位原来就是0,则出错停机。由于1个缓冲块有1024字节,即8192比特位, // ��� block/8192
-���ɼ����ָ���� block ����λͼ�е��ĸ����ϡ��� block&8191
-�� // 因此 block/8192
+即可计算出指定块 block 在逻辑位图中的哪个块上。而 block&8191
+可 // �Եõ�block������λͼ��ǰ���еı���ƫ��λ�á� // 以得到block在逻辑块位图当前块中的比特偏移位置。 67
-block -= sb->s_firstdatazone - 1 ; // ��block = block
+block -= sb->s_firstdatazone - 1 ; // 即block = block
- ( s_firstdatazone -1); 68
@@ -2182,7 +2182,7 @@ cleared\n"); 71
} // �������Ӧ����λͼ���ڻ��������ı�־�� // 最后置相应逻辑块位图所在缓冲区已修改标志。 72
sb->s_zmap[block/8192]->b_dirt = 1; 75 ////���豸����һ�����飨�̿飬���飩�� ////向设备申请一个逻辑块(盘块,区块)。 // ��������ȡ���豸�ij����飬���ڳ������е�����λͼ��Ѱ�ҵ�һ��0ֵ����λ������ // 函数首先取得设备的超级块,并在超级块中的逻辑块位图中寻找第一个0值比特位(代表 // һ���������飩��Ȼ����λ��Ӧ����������λͼ�еı���λ������Ϊ�������ڻ� // 一个空闲逻辑块)。然后置位对应逻辑块在逻辑块位图中的比特位。接着为该逻辑块在缓 // ������ȡ��һ���Ӧ����顣��û�������㣬���������Ѹ��±�־�����ı�־�� // 冲区中取得一块对应缓冲块。最后将该缓冲块清零,并设置其已更新标志和已修改标志。 // ����������š�����ִ�гɹ�������ţ��̿�ţ�������0�� // 并返回逻辑块号。函数执行成功则返回逻辑块号(盘块号),否则返回0。 76 int
new_block(int dev) 81 // ���Ȼ�ȡ�豸dev�ij����顣���ָ���豸�ij����鲻���ڣ������ͣ����Ȼ��ɨ���ļ� // 首先获取设备dev的超级块。如果指定设备的超级块不存在,则出错停机。然后扫描文件 // ϵͳ��8������λͼ��Ѱ����0ֵ����λ����Ѱ�ҿ������飬��ȡ���ø������ // 系统的8块逻辑块位图,寻找首个0值比特位,以寻找空闲逻辑块,获取放置该逻辑块的 // ��š� ���ȫ��ɨ����8������λͼ�����б���λ��i >= 8 �� j >= 8192����û�ҵ� // 块号。 如果全部扫描完8块逻辑块位图的所有比特位(i >= 8 或 j >= 8192)还没找到 // 0ֵ����λ����λͼ���ڵĻ����ָ����Ч(bh = NULL)�� ����0�˳���û�п������飩�� // 0值比特位或者位图所在的缓冲块指针无效(bh = NULL)则 返回0退出(没有空闲逻辑块)。 82
if (!(sb = get_super(dev))) 90
return 0; // ���������ҵ���������j��Ӧ����λͼ�еı���λ������Ӧ����λ�Ѿ���λ������� // 接着设置找到的新逻辑块j对应逻辑块位图中的比特位。若对应比特位已经置位,则出错 // ͣ���������ô��λͼ�Ķ�Ӧ�����������ı�־����Ϊ����λͼ����ʾ������������ // 停机。否则置存放位图的对应缓冲区块已修改标志。因为逻辑块位图仅表示盘上数据区中 // �����ռ�������������λͼ�б���λƫ��ֵ��ʾ����������ʼ������Ŀ�ţ���� // 逻辑块的占用情况,即逻辑块位图中比特位偏移值表示从数据区开始处算起的块号,因此 // ������Ҫ������������1������Ŀ�ţ���jת��������š���ʱ������������ // 这里需要加上数据区第1个逻辑块的块号,把j转换成逻辑块号。此时如果新逻辑块大于 // ���豸�ϵ�������������˵��ָ�������ڶ�Ӧ�豸�ϲ����ڡ�����ʧ�ܣ�����0�˳��� // 该设备上的总逻辑块数,则说明指定逻辑块在对应设备上不存在。申请失败,返回0退出。 91
if (set_bit(j,bh->b_data)) 96
return 0; // Ȼ���ڸ��ٻ�������Ϊ���豸��ָ���������ȡ��һ������飬�����ػ����ͷָ�롣 // 然后在高速缓冲区中为该设备上指定的逻辑块号取得一个缓冲块,并返回缓冲块头指针。 // ��Ϊ��ȡ�õ����������ô���һ��Ϊ1��getblk()�л����ã����������Ϊ1��ͣ���� // 因为刚取得的逻辑块其引用次数一定为1(getblk()中会设置),因此若不为1则停机。 // ������������㣬���������Ѹ��±�־�����ı�־��Ȼ���ͷŶ�Ӧ����飬���� // 最后将新逻辑块清零,并设置其已更新标志和已修改标志。然后释放对应缓冲块,返回 // ����š� // 逻辑块号。 97
if (!(bh=getblk(dev,j))) 107 //// �ͷ�ָ����i�ڵ㡣 //// 释放指定的i节点。 // �ú��������жϲ���������i�ڵ�ŵ���Ч�ԺͿ��ͷ��ԡ���i�ڵ���Ȼ��ʹ�������� // 该函数首先判断参数给出的i节点号的有效性和可释放性。若i节点仍然在使用中则不能 // ���ͷš�Ȼ�����ó�������Ϣ��i�ڵ�λͼ���в�������λi�ڵ�Ŷ�Ӧ��i�ڵ�λͼ�� // 被释放。然后利用超级块信息对i节点位图进行操作,复位i节点号对应的i节点位图中 // ����λ�������i�ڵ�ṹ�� // 比特位,并清空i节点结构。 108 void free_inode(struct buffer_head * bh; 112 // �����жϲ�����������Ҫ�ͷŵ�i�ڵ���Ч�Ի�Ϸ��ԡ����i�ڵ�ָ��=NULL�����˳��� // 首先判断参数给出的需要释放的i节点有效性或合法性。如果i节点指针=NULL,则退出。 // ���i�ڵ��ϵ��豸���ֶ�Ϊ0��˵���ýڵ�û��ʹ�á�������0��ն�Ӧi�ڵ���ռ�ڴ� // 如果i节点上的设备号字段为0,说明该节点没有使用。于是用0清空对应i节点所占内存 // �������ء�memset()������
-include/string.h ��395�п�ʼ���������ʾ��0��дinode // 区并返回。memset()定义在
+include/string.h 第395行开始处。这里表示用0填写inode // ָ��ָ������������ sizeof(*inode) ���ڴ�顣 // 指针指定处、长度是 sizeof(*inode) 的内存块。 113 if (!inode) 118 } // �����i�ڵ㻹�������������ã������ͷţ�˵���ں������⣬ͣ��������ļ������� // 如果此i节点还有其他程序引用,则不能释放,说明内核有问题,停机。如果文件连接数 // ��Ϊ0�����ʾ���������ļ�Ŀ¼����ʹ�øýڵ㣬���Ҳ��Ӧ�ͷţ���Ӧ�÷Żصȡ� // 不为0,则表示还有其他文件目录项在使用该节点,因此也不应释放,而应该放回等。 119 if
@@ -2436,24 +2436,24 @@ lang=EN-US> &nb
panic("trying to free inode with
links"); // ���ж���i�ڵ�ĺ�����֮�����ǿ�ʼ�����䳬������Ϣ�����е�i�ڵ�λͼ���в����� // 在判断完i节点的合理性之后,我们开始利用其超级块信息对其中的i节点位图进行操作。 // ����ȡi�ڵ������豸�ij����飬�����豸�Ƿ���ڡ�Ȼ���ж�i�ڵ�ŵķ�Χ�Ƿ���ȷ�� // 首先取i节点所在设备的超级块,测试设备是否存在。然后判断i节点号的范围是否正确, // ��� i�ڵ�ŵ���0 �� ���ڸ��豸�� i�ڵ��������������0��i�ڵ㱣��û��ʹ�ã��� // 如果 i节点号等于0 或 大于该设备上 i节点总数,则出错(0号i节点保留没有使用)。 // �����i�ڵ��Ӧ�Ľڵ�λͼ�����ڣ����������Ϊһ��������i�ڵ�λͼ�� 8192 �� // 如果该i节点对应的节点位图不存在,则出错。因为一个缓冲块的i节点位图有 8192 比 // ��λ�����i_num>>13����i_num/8192�����Եõ���ǰi�ڵ�����ڵ�s_imap[]����� // 特位。因此i_num>>13(即i_num/8192)可以得到当前i节点号所在的s_imap[]项,即所 // ���̿顣 // 在盘块。 125 if (!(sb = &nb
panic("nonexistent imap in
superblock"); // �������Ǹ�λi�ڵ��Ӧ�Ľڵ�λͼ�еı���λ������ñ���λ�Ѿ�����0������ʾ���� // 现在我们复位i节点对应的节点位图中的比特位。如果该比特位已经等于0,则显示出错 // ������Ϣ�������i�ڵ�λͼ���ڻ��������ı�־������ո�i�ڵ�ṹ��ռ�ڴ����� // 警告信息。最后置i节点位图所在缓冲区已修改标志,并清空该i节点结构所占内存区。 131 if ( } 136 //// Ϊ�豸dev����һ����i�ڵ㡣��ʼ�������ظ���i�ڵ��ָ�롣 //// 为设备dev建立一个新i节点。初始化并返回该新i节点的指针。 // ���ڴ�i�ڵ���л�ȡһ������i�ڵ�������i�ڵ�λͼ����һ������i�ڵ㡣 // 在内存i节点表中获取一个空闲i节点表项,并从i节点位图中找一个空闲i节点。 137 struct m_inode * int i,j; 143 // ���ȴ��ڴ�i�ڵ����inode_table���л�ȡһ������i�ڵ������ȡָ���豸�ij����� // 首先从内存i节点表(inode_table)中获取一个空闲i节点项,并读取指定设备的超级块 // �ṹ�� Ȼ��ɨ�賬������8��i�ڵ�λͼ��Ѱ����0����λ��Ѱ�ҿ��нڵ㣬��ȡ���� // 结构。 然后扫描超级块中8块i节点位图,寻找首个0比特位,寻找空闲节点,获取放置 // ��i�ڵ�Ľڵ�š����ȫ��ɨ���껹û�ҵ�������λͼ���ڵĻ������Ч��bh = NULL���� // 该i节点的节点号。如果全部扫描完还没找到,或者位图所在的缓冲块无效(bh = NULL), // ��Ż���ǰ�����i�ڵ���е�i�ڵ㣬�����ؿ�ָ���˳���û�п���i�ڵ㣩�� // 则放回先前申请的i节点表中的i节点,并返回空指针退出(没有空闲i节点)。 144 if (!(inode=get_empty_inode()))
-// fs/inode.c����197�� 145
@@ -2566,8 +2566,8 @@ return NULL; 146 if (!(sb = get_super(dev)))
- // fs/super.c����56�� 147
@@ -2608,15 +2608,15 @@ return NULL; 156 } // ���������Ѿ��ҵ��˻�δʹ�õ�i�ڵ��j��������λi�ڵ�j��Ӧ��i�ڵ�λͼ��Ӧ�� // 现在我们已经找到了还未使用的i节点号j。于是置位i节点j对应的i节点位图相应比 // ��λ������Ѿ���λ�����������Ȼ����i�ڵ�λͼ���ڻ�������ı�־������ʼ�� // 特位(如果已经置位,则出错)。然后置i节点位图所在缓冲块已修改标志。最后初始化 // ��i�ڵ�ṹ��i_ctime��i�ڵ����ݸı�ʱ�䣩�� // 该i节点结构(i_ctime是i节点内容改变时间)。 157 if ( bh->b_dirt = 1;
160
inode->i_count=1;
-// ���ü����� 161
inode->i_nlinks=1;
-// �ļ�Ŀ¼���������� 162 inode->i_dev=dev;
-// i�ڵ����ڵ��豸�š� 163 inode->i_uid=current->euid;
-// i�ڵ������û�id�� 164 inode->i_gid=current->egid;
-// ��id�� 165 inode->i_dirt=1;
-// ���ı�־��λ�� 166 inode->i_num = j
+ i*8192;
-// ��Ӧ�豸�е�i�ڵ�š� 167 inode->i_mtime =
inode->i_atime = inode->i_ctime = CURRENT_TIME;
-// ����ʱ�䡣 168 return inode;
-// ���ظ�i�ڵ�ָ�롣 169 } ����程序12-3 linux/fs/truncate.c 6 7
-#include <linux/sched.h> // ���ȳ���ͷ�ļ�������������ṹtask_struct������0���ݵȡ� 8 9
-#include <sys/stat.h> // �ļ�״̬ͷ�ļ��������ļ����ļ�ϵͳ״̬�ṹstat{}�ͳ����� 10 //// �ͷ�����һ�μ�ӿ顣���ڲ������� //// 释放所有一次间接块。(内部函数) // ����dev���ļ�ϵͳ�����豸���豸�ţ�block������š��ɹ���1������0�� // 参数dev是文件系统所在设备的设备号;block是逻辑块号。成功则返回1,否则返回0。 11
static int free_ind(int dev,int block) 16
int block_busy; //
-������û�б��ͷŵı�־�� 17 // �����жϲ�������Ч�ԡ���������Ϊ0���ء�Ȼ���ȡһ�μ�ӿ飬���ͷ����ϱ� // 首先判断参数的有效性。如果逻辑块号为0,则返回。然后读取一次间接块,并释放其上表 // ��ʹ�õ��������飬Ȼ���ͷŸ�һ�μ�ӿ�Ļ���顣
-����free_block()�����ͷ��豸 // 明使用的所有逻辑块,然后释放该一次间接块的缓冲块。
+函数free_block()用于释放设备 // ��ָ������ŵĴ��̿飨fs/bitmap.c��47�У��� // 上指定逻辑块号的磁盘块(fs/bitmap.c第47行)。 18
if (!block) 22
-p = (unsigned short *) bh->b_data; // ָ����������� 23
for (i=0;i<512;i++,p++)
-// ÿ�������Ͽ���512����š� 24
if (*p) 25
-if (free_block(dev,*p)) { // �ͷ�ָ�����豸���顣 26
-*p = 0; // ���㡣 27
-bh->b_dirt = 1; // �������ı�־�� 28
} else 29
-block_busy = 1; // ��������û���ͷű�־�� 30
brelse(bh);
- // Ȼ���ͷż�ӿ�ռ�õĻ���顣 31
} // ����ͷ��豸�ϵ�һ�μ�ӿ顣���������������û�б��ͷţ���0��ʧ�ܣ��� // 最后释放设备上的一次间接块。但如果其中有逻辑块没有被释放,则返回0(失败)。 32
if (block_busy) 35
return free_block(dev,block);
-// �ɹ���1������0�� 36 } 37 //// �ͷ����ж��μ�ӿ顣 //// 释放所有二次间接块。 // ����dev���ļ�ϵͳ�����豸���豸�ţ�block������š� // 参数dev是文件系统所在设备的设备号;block是逻辑块号。 38
static int free_dind(int dev,int block) 43
int block_busy;
-// ������û�б��ͷŵı�־�� 44 // �����жϲ�������Ч�ԡ���������Ϊ0���ء�Ȼ���ȡ���μ�ӿ��һ���飬���� // 首先判断参数的有效性。如果逻辑块号为0,则返回。然后读取二次间接块的一级块,并释 // �����ϱ���ʹ�õ��������飬Ȼ���ͷŸ�һ����Ļ���顣 // 放其上表明使用的所有逻辑块,然后释放该一级块的缓冲块。 45
if (!block) 49
-p = (unsigned short *) bh->b_data; // ָ����������� 50
for (i=0;i<512;i++,p++)
-// ÿ�������Ͽ�����512�������顣 51
if
(*p) 52
-if (free_ind(dev,*p)) { // �ͷ�����һ�μ�ӿ顣 53
-*p = 0; // ���㡣 54
-bh->b_dirt = 1; // �������ı�־�� 55
}
else 56
-block_busy = 1; // ��������û���ͷű�־�� 57
brelse(bh);
-// �ͷŶ��μ�ӿ�ռ�õĻ���顣 58
} // ����ͷ��豸�ϵĶ��μ�ӿ顣���������������û�б��ͷţ���0��ʧ�ܣ��� // 最后释放设备上的二次间接块。但如果其中有逻辑块没有被释放,则返回0(失败)。 59
if (block_busy) 64 //// �ض��ļ����ݺ����� //// 截断文件数据函数。 // ���ڵ��Ӧ���ļ����Ƚ�Ϊ0�����ͷ�ռ�õ��豸�ռ䡣 // 将节点对应的文件长度截为0,并释放占用的设备空间。 65
void truncate(struct 68
int block_busy;
-// ������û�б��ͷŵı�־�� 69 // �����ж�ָ��i�ڵ���Ч�ԡ�������dz����ļ���Ŀ¼�ļ���������ء� // 首先判断指定i节点有效性。如果不是常规文件、目录文件或链接项,则返回。 70
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || 72
return; // Ȼ���ͷ�i�ڵ��7��ֱ�����飬������7��������ȫ���㡣����free_block()���� // 然后释放i节点的7个直接逻辑块,并将这7个逻辑块项全置零。函数free_block()用于 // �ͷ��豸��ָ������ŵĴ��̿飨fs/bitmap.c��47�У�����������æ��û�б��ͷ� // 释放设备上指定逻辑块号的磁盘块(fs/bitmap.c第47行)。若有逻辑块忙而没有被释放 // ���ÿ�æ��־block_busy�� // 则置块忙标志block_busy。 73
repeat: 76
if (inode->i_zone[i]) {
-// �����Ų�Ϊ0�����ͷ�֮�� 77
if (free_block(inode->i_dev,inode->i_zone[i])) 78
-inode->i_zone[i]=0; // ��ָ����0�� 79
else 80
-block_busy = 1; // ��û���ͷŵ����ñ�־�� 81
} 82
if (free_ind(inode->i_dev,inode->i_zone[7]))
-// �ͷ�����һ�μ�ӿ顣 83
inode->i_zone[7] = 0;
-// ��ָ����0�� 84
else 85
block_busy = 1; //
-��û���ͷŵ����ñ�־�� 86
if (free_dind(inode->i_dev,inode->i_zone[8]))
-// �ͷ����ж��μ�ӿ顣 87
inode->i_zone[8] = 0;
-// ��ָ����0�� 88
else 89
block_busy = 1; //
-��û���ͷŵ����ñ�־�� // �˺�����i�ڵ����ı�־��������������������ڡ�æ����û�б��ͷţ���ѵ�ǰ���� // 此后设置i节点已修改标志,并且如果还有逻辑块由于“忙”而没有被释放,则把当前进程 // ����ʱ��Ƭ��0�����õ�ǰ�����ȱ��л�ȥ�����������̣��Ե�һ��������ִ���ͷŲ����� // 运行时间片置0,以让当前进程先被切换去运行其他进程,稍等一会再重新执行释放操作。 90
inode->i_dirt = 1; 92
current->counter = 0;
-// ��ǰ����ʱ��Ƭ��0�� 93
schedule(); 96
inode->i_size = 0;
-// �ļ���С���㡣 // ����������ļ���ʱ���i�ڵ�ı�ʱ��Ϊ��ǰʱ�䡣�� CURRENT_TIME ������ͷ�ļ� // 最后重新置文件修改时间和i节点改变时间为当前时间。宏 CURRENT_TIME 定义在头文件 // include/linux/sched.h��142�д�������Ϊ(startup_time + jiffies/HZ)������ȡ�ô� // include/linux/sched.h第142行处,定义为(startup_time + jiffies/HZ)。用于取得从 // 1970:0:0:0��ʼ������Ϊֹ������������ // 1970:0:0:0开始到现在为止经过的秒数。 97
inode->i_mtime = inode->i_ctime = CURRENT_TIME; 6 7
-#include <string.h> // �ַ���ͷ�ļ�����Ҫ������һЩ�й��ַ���������Ƕ�뺯���� 8
-#include <sys/stat.h> // �ļ�״̬ͷ�ļ��������ļ����ļ�ϵͳ״̬�ṹstat{}�ͳ����� 9 10
-#include <linux/sched.h> // ���ȳ���ͷ�ļ�������������ṹtask_struct������0�����ݣ�
- // ����һЩ�й��������������úͻ�ȡ��Ƕ��ʽ��ຯ������䡣 11
-#include <linux/kernel.h> // �ں�ͷ�ļ�������һЩ�ں˳��ú�����ԭ�ζ��塣 12
-#include <linux/mm.h> // �ڴ����ͷ�ļ�������ҳ���С�����һЩҳ���ͷź���ԭ�͡� 13
-#include <asm/system.h> // ϵͳͷ�ļ������������û���������/�ж��ŵȵ�Ƕ��ʽ���ꡣ 14 // �豸���ݿ�����ָ�����顣ÿ��ָ����ָ��ָ�����豸�ŵ��ܿ�������hd_sizes[]������ // 设备数据块总数指针数组。每个指针项指向指定主设备号的总块数数组hd_sizes[]。该总 // ��������ÿһ���Ӧ���豸��ȷ����һ�����豸����ӵ�е����ݿ�������1���С = 1KB���� // 块数数组每一项对应子设备号确定的一个子设备上所拥有的数据块总数(1块大小 = 1KB)。 15
extern int *blk_size[]; 17
struct m_inode inode_table[NR_INODE]={{0,},};
-// �ڴ���i�ڵ����NR_INODE=32��� 18 19
static void read_inode(struct m_inode * inode); // ��ָ��i�ڵ�ŵ�i�ڵ���Ϣ��297�С� 20
static void write_inode(struct m_inode * inode); // дi�ڵ���Ϣ�����ٻ����У�324�С� 21 //// �ȴ�ָ����i�ڵ���á� //// 等待指定的i节点可用。 // ���i�ڵ��ѱ���������ǰ������Ϊ�����жϵĵȴ�״̬�������ӵ���i�ڵ�ĵȴ��� // 如果i节点已被锁定,则将当前任务置为不可中断的等待状态,并添加到该i节点的等待队 // ��i_wait�С�ֱ����i�ڵ��������ȷ�ػ��ѱ����� // 列i_wait中。直到该i节点解锁并明确地唤醒本任务。 22
static inline void wait_on_inode(struct 26
sleep_on(&inode->i_wait);
-// kernel/sched.c����199�� 27
sti(); 29 //// ��i�ڵ�����������ָ����i�ڵ㣩�� //// 对i节点上锁(锁定指定的i节点)。 // ���i�ڵ��ѱ���������ǰ������Ϊ�����жϵĵȴ�״̬�������ӵ���i�ڵ�ĵȴ��� // 如果i节点已被锁定,则将当前任务置为不可中断的等待状态,并添加到该i节点的等待队 // ��i_wait�С�ֱ����i�ڵ��������ȷ�ػ��ѱ�����Ȼ����������� // 列i_wait中。直到该i节点解锁并明确地唤醒本任务。然后对其上锁。 30
static inline void lock_inode(struct 35
inode->i_lock=1;
-// ��������־�� 36
sti(); 38 //// ��ָ����i�ڵ������ //// 对指定的i节点解锁。 // ��λi�ڵ��������־������ȷ�ػ��ѵȴ��ڴ�i�ڵ�ȴ�����i_wait�ϵ����н��̡� // 复位i节点的锁定标志,并明确地唤醒等待在此i节点等待队列i_wait上的所有进程。 39
static inline void unlock_inode(struct 42
wake_up(&inode->i_wait);
-// kernel/sched.c����204�С� 43 } 44 //// �ͷ��豸dev���ڴ�i�ڵ���е�����i�ڵ㡣 //// 释放设备dev在内存i节点表中的所有i节点。 // ɨ���ڴ��е�i�ڵ�����飬�����ָ���豸ʹ�õ�i�ڵ���ͷ�֮�� // 扫描内存中的i节点表数组,如果是指定设备使用的i节点就释放之。 45
void invalidate_inodes(int dev) 49 // ������ָ��ָ���ڴ�i�ڵ���������Ȼ��ɨ��i�ڵ��ָ�������е�����i�ڵ㡣��� // 首先让指针指向内存i节点表数组首项。然后扫描i节点表指针数组中的所有i节点。针对 // ����ÿ��i�ڵ㣬�ȵȴ���i�ڵ�������ã���Ŀǰ���������Ļ��������ж��Ƿ�����ָ�� // 其中每个i节点,先等待该i节点解锁可用(若目前正被上锁的话),再判断是否属于指定 // �豸��i�ڵ㡣�����ָ���豸��i�ڵ㣬�����Ƿ�ʹ���ţ��������ü����Ƿ� // 设备的i节点。如果是指定设备的i节点,则看看它是否还被使用着,即其引用计数是否不 // Ϊ0����������ʾ������Ϣ��Ȼ���ͷ�֮������i�ڵ���豸���ֶ�i_dev��0����50���� // 为0。若是则显示警告信息。然后释放之,即把i节点的设备号字段i_dev置0。第50行上 // ��ָ�븳ֵ "0+inode_table " ��ͬ�� "inode_table"��"&inode_table[0] "����������д // 的指针赋值 "0+inode_table " 等同于 "inode_table"、"&inode_table[0] "。不过这样写 // ���ܸ�����һЩ�� // 可能更明了一些。 50
inode = 0+inode_table;
-// ָ��i�ڵ��ָ��������� 51
for(i=0 ; i<NR_INODE ; i++,inode++) { 52
wait_on_inode(inode);
-// �ȴ���i�ڵ���ã��������� 53
if (inode->i_dev == dev) { 54
-if (inode->i_count) // ������������Ϊ0������ʾ�������档 55
printk("inode in use on removed
disk\n\r"); 56
-inode->i_dev = inode->i_dirt = 0; // �ͷ�i�ڵ�(���豸��Ϊ0)�� 57
} 60 //// ͬ������i�ڵ㡣 //// 同步所有i节点。 // ���ڴ�i�ڵ��������i�ڵ����豸��i�ڵ���ͬ�������� // 把内存i节点表中所有i节点与设备上i节点作同步操作。 61
void sync_inodes(void) 65 // �������ڴ�i�ڵ����͵�ָ��ָ��i�ڵ�����Ȼ��ɨ������i�ڵ���еĽڵ㡣��� // 首先让内存i节点类型的指针指向i节点表首项,然后扫描整个i节点表中的节点。针对 // ����ÿ��i�ڵ㣬�ȵȴ���i�ڵ�������ã���Ŀǰ���������Ļ�����Ȼ���жϸ�i�ڵ� // 其中每个i节点,先等待该i节点解锁可用(若目前正被上锁的话),然后判断该i节点 // �Ƿ��ѱ��IJ��Ҳ��ǹܵ��ڵ㡣�������������i�ڵ�д����ٻ������С������� // 是否已被修改并且不是管道节点。若是这种情况则将该i节点写入高速缓冲区中。缓冲区 // ��������buffer.c�����ʵ�ʱ��������д�����С� // 管理程序buffer.c会在适当时机将它们写入盘中。 66
inode = 0+inode_table;
-// ��ָ������ָ��i�ڵ��ָ��������� 67
for(i=0 ; i<NR_INODE
-; i++,inode++) { // ɨ��i�ڵ��ָ�����顣 68
wait_on_inode(inode);
-// �ȴ���i�ڵ���ã��������� 69
-if (inode->i_dirt && !inode->i_pipe) // ��i�ڵ������Ҳ��ǹܵ��ڵ㣬 70
write_inode(inode); //
-��д�̣�ʵ����д�뻺�����У��� 71
} 73 //// �ļ����ݿ�ӳ�䵽�̿�Ĵ�����������blockλͼ����������bmap - block map�� //// 文件数据块映射到盘块的处理操作。(block位图处理函数,bmap - block map) // ������inode
-�C �ļ���i�ڵ�ָ�룻block �C �ļ��е����ݿ�ţ�create - �������־�� // 参数:inode
+– 文件的i节点指针;block – 文件中的数据块号;create - 创建块标志。 // �ú�����ָ�����ļ����ݿ�block��Ӧ���豸�������ϣ�����������š����������־ // 该函数把指定的文件数据块block对应到设备上逻辑块上,并返回逻辑块号。如果创建标志 // ��λ�������豸�϶�Ӧ���鲻����ʱ�������´��̿飬�����ļ����ݿ�block��Ӧ���豸 // 置位,则在设备上对应逻辑块不存在时就申请新磁盘块,返回文件数据块block对应在设备 // �ϵ�����ţ��̿�ţ��� // 上的逻辑块号(盘块号)。 74
static int _bmap(struct 78 // �����жϲ����ļ����ݿ��block����Ч�ԡ�������С��0����ͣ���������Ŵ���ֱ�� // 首先判断参数文件数据块号block的有效性。如果块号小于0,则停机。如果块号大于直接 // ���� + ��ӿ��� + ���μ�ӿ����������ļ�ϵͳ��ʾ��Χ����ͣ���� // 块数 + 间接块数 + 二次间接块数,超出文件系统表示范围,则停机。 79
if (block<0) 82
panic("_bmap: block>big"); // Ȼ������ļ���ŵĴ�Сֵ���Ƿ������˴�����־�ֱ���д���������ÿ��С��7����ʹ // 然后根据文件块号的大小值和是否设置了创建标志分别进行处理。如果该块号小于7,则使 // ��ֱ�ӿ��ʾ�����������־��λ������i�ڵ��ж�Ӧ�ÿ�����飨���Σ��ֶ�Ϊ0���� // 用直接块表示。如果创建标志置位,并且i节点中对应该块的逻辑块(区段)字段为0,则 // ����Ӧ�豸����һ���̿飨���飩�����ҽ���������ţ��̿�ţ����������ֶ��С� // 向相应设备申请一磁盘块(逻辑块),并且将盘上逻辑块号(盘块号)填入逻辑块字段中。 // Ȼ������i�ڵ�ı�ʱ�䣬��i�ڵ����ı�־�� �������š� ����new_block() // 然后设置i节点改变时间,置i节点已修改标志。 最后返回逻辑块号。 函数new_block() // ������bitmap.c�����е�76�п�ʼ���� // 定义在bitmap.c程序中第76行开始处。 83
if (block<7) { 86
inode->i_ctime=CURRENT_TIME; // ctime
-- Change time�� 87
inode->i_dirt=1;
-// �������ı�־�� 88
} 90
} // ����ÿ��>=7����С��7+512����˵��ʹ�õ���һ�μ�ӿ顣�����һ�μ�ӿ���д����� // 如果该块号>=7,且小于7+512,则说明使用的是一次间接块。下面对一次间接块进行处理。 // ����Ǵ��������Ҹ�i�ڵ��ж�Ӧ��ӿ��ֶ�i_zone[7]��0�������ļ����״�ʹ�ü�ӿ飬 // 如果是创建,并且该i节点中对应间接块字段i_zone[7]是0,表明文件是首次使用间接块, // ��������һ���̿����ڴ�ż�ӿ���Ϣ��������ʵ�ʴ��̿�������ӿ��ֶ��С�
-Ȼ���� // 则需申请一磁盘块用于存放间接块信息,并将此实际磁盘块号填入间接块字段中。
+然后设 // ��i�ڵ����ı�־����ʱ�䡣
-�������ʱ������̿�ʧ�ܣ����ʱi�ڵ��ӿ��ֶ� // 置i节点已修改标志和修改时间。
+如果创建时申请磁盘块失败,则此时i节点间接块字段 // i_zone[7]Ϊ0����0�����߲��Ǵ�������i_zone[7]ԭ����Ϊ0������i�ڵ���û�м� // i_zone[7]为0,则返回0。或者不是创建,但i_zone[7]原来就为0,表明i节点中没有间 // �ӿ飬����ӳ����̿�ʧ�ܣ�����0�˳��� // 接块,于是映射磁盘块失败,返回0退出。 91
block -= 7; // ���ڶ�ȡ�豸�ϸ�i�ڵ��һ�μ�ӿ顣��ȡ�ü�ӿ��ϵ�block���е�����ţ��̿� // 现在读取设备上该i节点的一次间接块。并取该间接块上第block项中的逻辑块号(盘块 // �ţ�i��ÿһ��ռ2���ֽڡ�����Ǵ������Ҽ�ӿ�ĵ�block���е������Ϊ0�Ļ��� // 号)i。每一项占2个字节。如果是创建并且间接块的第block项中的逻辑块号为0的话, // ������һ���̿飬���ü�ӿ��еĵ�block����ڸ��������š�Ȼ����λ��ӿ���� // 则申请一磁盘块,并让间接块中的第block项等于该新逻辑块块号。然后置位间接块的已 // �ı�־��������Ǵ�������i������Ҫӳ�䣨Ѱ�ң�������š� // 修改标志。如果不是创建,则i就是需要映射(寻找)的逻辑块号。 100
@@ -2316,8 +2316,8 @@ bh->b_dirt=1; // ����ͷŸü�ӿ�ռ�õĻ���飬�����ش������������ԭ�еĶ�Ӧblock�������š� // 最后释放该间接块占用的缓冲块,并返回磁盘上新申请或原有的对应block的逻辑块块号。 108
@@ -2330,25 +2330,25 @@ return i; 110 } // ���������е��ˣ���������ݿ����ڶ��μ�ӿ顣�䴦��������һ�μ�ӿ����ơ������Ƕ� // 若程序运行到此,则表明数据块属于二次间接块。其处理过程与一次间接块类似。下面是对 // ���μ�ӿ�Ĵ��������Ƚ�block�ټ�ȥ��ӿ������ɵĿ�����512����Ȼ������Ƿ����� // 二次间接块的处理。首先将block再减去间接块所容纳的块数(512)。然后根据是否设置 // �˴�����־���д�����Ѱ�Ҵ�����������´�������i�ڵ�Ķ��μ�ӿ��ֶ�Ϊ0�������� // 了创建标志进行创建或寻找处理。如果是新创建并且i节点的二次间接块字段为0,则需申 // ��һ���̿����ڴ�Ŷ��μ�ӿ��һ������Ϣ��������ʵ�ʴ��̿��������μ�ӿ��ֶ� // 请一磁盘块用于存放二次间接块的一级块信息,并将此实际磁盘块号填入二次间接块字段 // �С�֮����i�ڵ����ı��ƺ���ʱ�䡣ͬ���أ��������ʱ������̿�ʧ�ܣ���� // 中。之后,置i节点已修改编制和修改时间。同样地,如果创建时申请磁盘块失败,则此 // ʱi�ڵ���μ�ӿ��ֶ�i_zone[8]Ϊ0����0�����߲��Ǵ�������i_zone[8]ԭ���� // 时i节点二次间接块字段i_zone[8]为0,则返回0。或者不是创建,但i_zone[8]原来就 // Ϊ0������i�ڵ���û�м�ӿ飬����ӳ����̿�ʧ�ܣ�����0�˳��� // 为0,表明i节点中没有间接块,于是映射磁盘块失败,返回0退出。 111 block -= 512; // ���ڶ�ȡ�豸�ϸ�i�ڵ�Ķ��μ�ӿ顣��ȡ�ö��μ�ӿ��һ�����ϵ� (block/512) // 现在读取设备上该i节点的二次间接块。并取该二次间接块的一级块上第 (block/512) // ���е������i������Ǵ������Ҷ��μ�ӿ��һ�����ϵ� (block/512) ���е��� // 项中的逻辑块号i。如果是创建并且二次间接块的一级块上第 (block/512) 项中的逻辑 // ���Ϊ0�Ļ�����������һ���̿飨���飩��Ϊ���μ�ӿ�Ķ�����i�����ö��μ�� // 块号为0的话,则需申请一磁盘块(逻辑块)作为二次间接块的二级块i,并让二次间接 // ���һ�����е� (block/512)����ڸö�����Ŀ��i��Ȼ����λ���μ�ӿ��һ������ // 块的一级块中第 (block/512)项等于该二级块的块号i。然后置位二次间接块的一级块已 // �ı�־�����ͷŶ��μ�ӿ��һ���顣������Ǵ�������i������Ҫӳ�䣨Ѱ�ң����� // 修改标志。并释放二次间接块的一级块。如果不是创建,则i就是需要映射(寻找)的逻 // ����š� // 辑块号。 119 if (!(bh= &nb
lang=EN-US> brelse(bh); // ������μ�ӿ�Ķ�������Ϊ0����ʾ������̿�ʧ�ܻ���ԭ����Ӧ��ž�Ϊ0���� // 如果二次间接块的二级块块号为0,表示申请磁盘块失败或者原来对应块号就为0,则返 // ��0�˳�������ʹ��豸�϶�ȡ���μ�ӿ�Ķ����飬��ȡ�ö������ϵ�block���е��� // 回0退出。否则就从设备上读取二次间接块的二级块,并取该二级块上第block项中的逻 // ����ţ�����511��Ϊ����blockֵ������511���� // 辑块号(与上511是为了限定block值不超过511)。 128 if (!i) // ����Ǵ������Ҷ�����ĵ�block���������Ϊ0�Ļ���������һ���̿飨���飩�� // 如果是创建并且二级块的第block项中逻辑块号为0的话,则申请一磁盘块(逻辑块), // ��Ϊ���մ��������Ϣ�Ŀ顣���ö������еĵ�block����ڸ���������(i)��Ȼ�� // 作为最终存放数据信息的块。并让二级块中的第block项等于该新逻辑块块号(i)。然后 // ��λ����������ı�־�� // 置位二级块的已修改标志。 133 if (create
@@ -2491,8 +2491,8 @@ bh->b_dirt=1; // ����ͷŸö��μ�ӿ�Ķ����飬���ش�����������Ļ�ԭ�еĶ�Ӧblock�������š� // 最后释放该二次间接块的二级块,返回磁盘上新申请的或原有的对应block的逻辑块块号。 138 } 141 //// ȡ�ļ����ݿ�block���豸�϶�Ӧ������š� //// 取文件数据块block在设备上对应的逻辑块号。 // ������inode
-�C �ļ����ڴ�i�ڵ�ָ�룻block �C �ļ��е����ݿ�š� // 参数:inode
+– 文件的内存i节点指针;block – 文件中的数据块号。 // �������ɹ��ض�Ӧ������ţ�����0�� // 若操作成功则返回对应的逻辑块号,否则返回0。 142 int bmap(struct } 146 //// ȡ�ļ����ݿ�block���豸�϶�Ӧ������š������Ӧ�����鲻���ھʹ���һ�顣 //// 取文件数据块block在设备上对应的逻辑块号。如果对应的逻辑块不存在就创建一块。 // �������豸�϶�Ӧ������š� // 并返回设备上对应的逻辑块号。 // ������inode
-�C �ļ����ڴ�i�ڵ�ָ�룻block �C �ļ��е����ݿ�š� // 参数:inode
+– 文件的内存i节点指针;block – 文件中的数据块号。 // �������ɹ��ض�Ӧ������ţ�����0�� // 若操作成功则返回对应的逻辑块号,否则返回0。 147 int create_block(struct } //// �Żأ����ã�һ��i�ڵ�(��д���豸)�� //// 放回(放置)一个i节点(回写入设备)。 // �ú�����Ҫ���ڰ�i�ڵ����ü���ֵ�ݼ�1���������ǹܵ�i�ڵ㣬���ѵȴ��Ľ��̡� // 该函数主要用于把i节点引用计数值递减1,并且若是管道i节点,则唤醒等待的进程。 // ���ǿ��豸�ļ�i�ڵ���ˢ���豸��������i�ڵ�����Ӽ���Ϊ0�����ͷŸ�i�ڵ�ռ�� // 若是块设备文件i节点则刷新设备。并且若i节点的链接计数为0,则释放该i节点占用 // �����д������飬���ͷŸ�i�ڵ㡣 // 的所有磁盘逻辑块,并释放该i节点。 152 void iput(struct m_inode * inode) 153 { // �����жϲ���������i�ڵ����Ч�ԣ����ȴ�inode�ڵ����������������Ļ�������� // 首先判断参数给出的i节点的有效性,并等待inode节点解锁(如果已上锁的话)。如果i // �ڵ�����ü���Ϊ0����ʾ��i�ڵ��Ѿ��ǿ��еġ��ں���Ҫ�������зŻز�����˵���� // 节点的引用计数为0,表示该i节点已经是空闲的。内核再要求对其进行放回操作,说明内 // �����������������⡣������ʾ������Ϣ��ͣ���� // 核中其他代码有问题。于是显示错误信息并停机。 154 if (!inode) // ����ǹܵ�i�ڵ㣬���ѵȴ��ùܵ��Ľ��̣����ô�����1��������������ء����� // 如果是管道i节点,则唤醒等待该管道的进程,引用次数减1,如果还有引用则返回。否则 // �ͷŹܵ�ռ�õ��ڴ�ҳ�棬����λ�ýڵ�����ü���ֵ�����ı�־�ܵ���־�������ء� // 释放管道占用的内存页面,并复位该节点的引用计数值、已修改标志和管道标志,并返回。 // ���ڹܵ��ڵ㣬inode->i_size������ڴ�ҳ��ַ���μ�get_pipe_inode()��231��237�С� // 对于管道节点,inode->i_size存放着内存页地址。参见get_pipe_inode(),231,237行。 159 if
@@ -2664,11 +2664,11 @@ return; 169 } // ���i�ڵ��Ӧ���豸�� = 0���˽ڵ�����ü����ݼ�1�����ء��������ڹܵ������� // 如果i节点对应的设备号 = 0,则将此节点的引用计数递减1,返回。例如用于管道操作的 // i�ڵ㣬��i�ڵ���豸��Ϊ0�� // i节点,其i节点的设备号为0。 170 if
@@ -2685,10 +2685,10 @@ return; 173 } // ����ǿ��豸�ļ���i�ڵ㣬��ʱ�����ֶ�0��i_zone[0]�������豸�ţ���ˢ�¸��豸�� // 如果是块设备文件的i节点,此时逻辑块字段0(i_zone[0])中是设备号,则刷新该设备。 // ���ȴ�i�ڵ������ // 并等待i节点解锁。 174 if ( &nb
177 } // ���i�ڵ�����ü�������1��������ݼ�1���ֱ�ӷ��أ���Ϊ��i�ڵ㻹�������ã����� // 如果i节点的引用计数大于1,则计数递减1后就直接返回(因为该i节点还有人在用,不能 // �ͷţ��������˵��i�ڵ�����ü���ֵΪ1����Ϊ��157���Ѿ��жϹ����ü����Ƿ�Ϊ�㣩�� // 释放),否则就说明i节点的引用计数值为1(因为第157行已经判断过引用计数是否为零)。 // ���i�ڵ��������Ϊ0����˵��i�ڵ��Ӧ�ļ���ɾ���������ͷŸ�i�ڵ���������飬 // 如果i节点的链接数为0,则说明i节点对应文件被删除。于是释放该i节点的所有逻辑块, // ���ͷŸ�i�ڵ㡣����free_inode()����ʵ���ͷ�i�ڵ����������λi�ڵ��Ӧ��i�ڵ�λ // 并释放该i节点。函数free_inode()用于实际释放i节点操作,即复位i节点对应的i节点位 // ͼ����λ�����i�ڵ�ṹ���ݡ� // 图比特位,清空i节点结构内容。 178 repeat: 185
free_inode(inode);
-// bitmap.c ��108�п�ʼ���� 186
@@ -2760,14 +2760,14 @@ return; 187 } // �����i�ڵ��������ģ����д���¸�i�ڵ㣬���ȴ���i�ڵ����������������дi�� // 如果该i节点已作过修改,则回写更新该i节点,并等待该i节点解锁。由于这里在写i节 // ��ʱ��Ҫ�ȴ�˯�ߣ���ʱ���������п����ĸ�i�ڵ㣬����ڽ��̱����Ѻ���Ҫ�ٴ��ظ� // 点时需要等待睡眠,此时其他进程有可能修改该i节点,因此在进程被唤醒后需要再次重复 // ���������жϹ��̣�repeat���� // 进行上述判断过程(repeat)。 188 if
@@ -2781,7 +2781,7 @@ lang=EN-US> &nb
190
wait_on_inode(inode);
-/* ��Ϊ����˯���ˣ�������Ҫ�ظ��ж� */ 191
@@ -2790,14 +2790,14 @@ goto repeat; 192 } // ��������ִ�е��ˣ���˵����i�ڵ�����ü���ֵi_count��1����������Ϊ�㣬�������� // 程序若能执行到此,则说明该i节点的引用计数值i_count是1、链接数不为零,并且内容 // û�б��Ĺ�����˴�ʱֻҪ��i�ڵ����ü����ݼ�1�����ء���ʱ��i�ڵ��i_count=0�� // 没有被修改过。因此此时只要把i节点引用计数递减1,返回。此时该i节点的i_count=0, // ��ʾ���ͷš� // 表示已释放。 193
@@ -2812,12 +2812,12 @@ lang=EN-US> } 196 //// ��i�ڵ����inode_table���л�ȡһ������i�ڵ�� //// 从i节点表(inode_table)中获取一个空闲i节点项。 // Ѱ�����ü���countΪ0��i�ڵ㣬������д�̺����㣬������ָ�롣���ü�������1�� // 寻找引用计数count为0的i节点,并将其写盘后清零,返回其指针。引用计数被置1。 197 struct m_inode * m_inode * inode; 200 static struct m_inode * last_inode = inode_table; // ָ��i�ڵ����1� 201 int i; 202 // �ڳ�ʼ��last_inodeָ��ָ��i�ڵ��ͷһ���ѭ��ɨ������i�ڵ������� // 在初始化last_inode指针指向i节点表头一项后循环扫描整个i节点表。如果last_inode // �Ѿ�ָ��i�ڵ�������1��֮������������ָ��i�ڵ����ʼ�����Լ���ѭ��Ѱ�ҿ��� // 已经指向i节点表的最后1项之后,则让其重新指向i节点表开始处,以继续循环寻找空闲 // i�ڵ����� last_inode��ָ���i�ڵ�ļ���ֵΪ0����˵�������ҵ�����i�ڵ�� // i节点项。如果 last_inode所指向的i节点的计数值为0,则说明可能找到空闲i节点项。 // ��inodeָ���i�ڵ㡣�����i�ڵ�����ı�־��������־��Ϊ0�������ǿ���ʹ�ø� // 让inode指向该i节点。如果该i节点的已修改标志和锁定标志均为0,则我们可以使用该 // i�ڵ㣬�����˳�forѭ���� // i节点,于是退出for循环。 203 do { 205
for (i = NR_INODE; i ; i--) {
-// NR_INODE = 32�� 206
@@ -2905,8 +2905,8 @@ lang=EN-US> &nb
lang=EN-US>
} // ���û���ҵ�����i�ڵ㣨inode = NULL������i�ڵ����ӡ����������ʹ�ã���ͣ���� // 如果没有找到空闲i节点(inode = NULL),则将i节点表打印出来供调试使用,并停机。 214
@@ -2934,11 +2934,11 @@ mem"); // �ȴ���i�ڵ����������ֱ������Ļ����������i�ڵ����ı�־����λ�Ļ����� // 等待该i节点解锁(如果又被上锁的话)。如果该i节点已修改标志被置位的话,则将该 // i�ڵ�ˢ�£�ͬ��������Ϊˢ��ʱ���ܻ�˯�ߣ������Ҫ�ٴ�ѭ���ȴ���i�ڵ������ // i节点刷新(同步)。因为刷新时可能会睡眠,因此需要再次循环等待该i节点解锁。 220
@@ -2964,14 +2964,14 @@ lang=EN-US> &nb
lang=EN-US> } while
(inode->i_count); // ���i�ڵ��ֱ�����ռ�õĻ���i�ڵ�ļ���ֵ��Ϊ0�ˣ���������Ѱ�ҿ���i�ڵ㡣���� // 如果i节点又被其他占用的话(i节点的计数值不为0了),则重新寻找空闲i节点。否则 // ˵�����ҵ�����Ҫ��Ŀ���i�ڵ����i�ڵ����������㣬�������ü���Ϊ1������ // 说明已找到符合要求的空闲i节点项。则将该i节点项内容清零,并置引用计数为1,返回 // ��i�ڵ�ָ�롣 // 该i节点指针。 226 } 230 //// ��ȡ�ܵ��ڵ㡣 //// 获取管道节点。 // ����ɨ��i�ڵ����Ѱ��һ������i�ڵ��Ȼ��ȡ��һҳ�����ڴ湩�ܵ�ʹ�á�Ȼ�� // 首先扫描i节点表,寻找一个空闲i节点项,然后取得一页空闲内存供管道使用。然后将得 // ����i�ڵ�����ü�����Ϊ2(���ߺ�д��)����ʼ���ܵ�ͷ��β����i�ڵ�Ĺܵ����ͱ�ʾ�� // 到的i节点的引用计数置为2(读者和写者),初始化管道头和尾,置i节点的管道类型表示。 // ����Ϊi�ڵ�ָ�룬���ʧ����NULL�� // 返回为i节点指针,如果失败则返回NULL。 231 struct m_inode * m_inode * inode; 234 // ���ȴ��ڴ�i�ڵ����ȡ��һ������i�ڵ㡣����Ҳ�������i�ڵ���NULL��Ȼ��Ϊ�� // 首先从内存i节点表中取得一个空闲i节点。如果找不到空闲i节点则返回NULL。然后为该 // i�ڵ�����һҳ�ڴ棬���ýڵ��i_size�ֶ�ָ���ҳ�档�����û�п����ڴ棬���ͷŸ� // i节点申请一页内存,并让节点的i_size字段指向该页面。如果已没有空闲内存,则释放该 // i�ڵ㣬������NULL�� // i节点,并返回NULL。 235 if (!(inode = NULL; 237 if
(!(inode->i_size=get_free_page())) {
- // �ڵ��i_size�ֶ�ָ������ 238
@@ -3048,31 +3048,31 @@ return NULL; 240 } // Ȼ�����ø�i�ڵ�����ü���Ϊ2������λ��λ�ܵ�ͷβָ�롣i�ڵ���������� // 然后设置该i节点的引用计数为2,并复位复位管道头尾指针。i节点逻辑块号数组i_zone[] // ��i_zone[0]��i_zone[1]�зֱ�������Źܵ�ͷ�ܵ�βָ�롣�������i�ڵ��ǹܵ�i�� // 的i_zone[0]和i_zone[1]中分别用来存放管道头和管道尾指针。最后设置i节点是管道i节 // ���־�����ظ�i�ڵ�š� // 点标志并返回该i节点号。 241 inode->i_count =
2; /* sum of readers/writers */
-/* ��/д�����ܼ� */ 242 PIPE_HEAD(*inode) = PIPE_TAIL(*inode)
-= 0; // ��λ�ܵ�ͷβָ�롣 243 inode->i_pipe =
1;
-// �ýڵ�Ϊ�ܵ�ʹ�õı�־�� 244 return inode; 246 //// ȡ��һ��i�ڵ㡣 //// 取得一个i节点。 // ������dev
-- �豸�ţ�nr - i�ڵ�š� // 参数:dev
+- 设备号;nr - i节点号。 // ���豸�϶�ȡָ���ڵ�ŵ�i�ڵ�ṹ���ݵ��ڴ�i�ڵ���У����ҷ��ظ�i�ڵ�ָ�롣 // 从设备上读取指定节点号的i节点结构内容到内存i节点表中,并且返回该i节点指针。 // ������λ�ڸ��ٻ������е�i�ڵ������Ѱ�����ҵ�ָ���ڵ�ŵ�i�ڵ����ھ���һЩ�ж� // 首先在位于高速缓冲区中的i节点表中搜寻,若找到指定节点号的i节点则在经过一些判断 // �����ظ�i�ڵ�ָ�롣������豸dev�϶�ȡָ��i�ڵ�ŵ�i�ڵ���Ϣ����i�ڵ�� // 处理后返回该i节点指针。否则从设备dev上读取指定i节点号的i节点信息放入i节点表 // �У������ظ�i�ڵ�ָ�롣 // 中,并返回该i节点指针。 247 struct m_inode * m_inode * inode, * empty; 250 // �����жϲ�����Ч�ԡ����豸����0��������ں˴������⣬��ʾ������Ϣ��ͣ����Ȼ��Ԥ // 首先判断参数有效性。若设备号是0,则表明内核代码问题,显示出错信息并停机。然后预 // �ȴ�i�ڵ����ȡһ������i�ڵ㱸�á� // 先从i节点表中取一个空闲i节点备用。 251 if (!dev) // ����ɨ��i�ڵ����Ѱ�Ҳ���ָ���ڵ��nr��i�ڵ㡣�������ýڵ�����ô���������� // 接着扫描i节点表。寻找参数指定节点号nr的i节点。并递增该节点的引用次数。如果当 // ǰɨ��i�ڵ���豸�Ų�����ָ�����豸�Ż��߽ڵ�Ų�����ָ���Ľڵ�ţ������ɨ�衣 // 前扫描i节点的设备号不等于指定的设备号或者节点号不等于指定的节点号,则继续扫描。 254 inode = // ����ҵ�ָ���豸��dev �ͽڵ�� nr ��i�ڵ㣬��ȴ��ýڵ����������������Ļ����� // 如果找到指定设备号dev 和节点号 nr 的i节点,则等待该节点解锁(如果已上锁的话)。 // �ڵȴ��ýڵ���������У�i�ڵ�����ܻᷢ���仯�������ٴν���������ͬ�жϡ������ // 在等待该节点解锁过程中,i节点表可能会发生变化。所以再次进行上述相同判断。如果发 // ���˱仯�����ٴ�����ɨ������i�ڵ���� // 生了变化,则再次重新扫描整个i节点表。 260
@@ -3193,17 +3193,17 @@ continue; // �������ʾ�ҵ���Ӧ��i�ڵ㡣���ǽ���i�ڵ����ü�����1��Ȼ��������һ����飬���� // 到这里表示找到相应的i节点。于是将该i节点引用计数增1。然后再作进一步检查,看它 // �Ƿ�����һ���ļ�ϵͳ�İ�װ�㡣������Ѱ�ұ���װ�ļ�ϵͳ���ڵ㲢���ء������i�ڵ� // 是否是另一个文件系统的安装点。若是则寻找被安装文件系统根节点并返回。如果该i节点 // ��ȷ�������ļ�ϵͳ�İ�װ�㣬���ڳ����������Ѱ��װ�ڴ�i�ڵ�ij����顣���û���� // 的确是其他文件系统的安装点,则在超级块表中搜寻安装在此i节点的超级块。如果没有找 // ��������ʾ������Ϣ�����Żر�������ʼʱ��ȡ�Ŀ��нڵ�empty�����ظ�i�ڵ�ָ�롣 // 到,则显示出错信息,并放回本函数开始时获取的空闲节点empty,返回该i节点指针。 265
@@ -3257,15 +3257,15 @@ return inode; // ִ�е������ʾ�Ѿ��ҵ���װ��inode�ڵ���ļ�ϵͳ�����顣���ǽ���i�ڵ�д�̷Żأ� // 执行到这里表示已经找到安装到inode节点的文件系统超级块。于是将该i节点写盘放回, // ���Ӱ�װ�ڴ�i�ڵ��ϵ��ļ�ϵͳ��������ȡ�豸�ţ�����i�ڵ��ΪROOT_INO����Ϊ1�� // 并从安装在此i节点上的文件系统超级块中取设备号,并令i节点号为ROOT_INO,即为1。 // Ȼ������ɨ������i�ڵ�����Ի�ȡ�ñ���װ�ļ�ϵͳ�ĸ�i�ڵ���Ϣ�� // 然后重新扫描整个i节点表,以获取该被安装文件系统的根i节点信息。 278
@@ -3291,10 +3291,10 @@ continue; // ���������ҵ�����Ӧ��i�ڵ㡣��˿��Է�����������ʼ����ʱ����Ŀ���i�ڵ㣬���� // 最终我们找到了相应的i节点。因此可以放弃本函数开始处临时申请的空闲i节点,返回 // �ҵ���i�ڵ�ָ�롣 // 找到的i节点指针。 284
@@ -3311,13 +3311,13 @@ inode; 287 } // ���������i�ڵ����û���ҵ�ָ����i�ڵ㣬������ǰ������Ŀ���i�ڵ�empty�� // 如果我们在i节点表中没有找到指定的i节点,则利用前面申请的空闲i节点empty在i // �ڵ���н�����i�ڵ㡣������Ӧ�豸�϶�ȡ��i�ڵ���Ϣ�����ظ�i�ڵ�ָ�롣 // 节点表中建立该i节点。并从相应设备上读取该i节点信息,返回该i节点指针。 288 if (!empty) 291 inode->i_dev =
dev;
-// ����i�ڵ���豸�� 292 inode->i_num =
nr;
-// ����i�ڵ�š� 293 } 296 //// ��ȡָ��i�ڵ���Ϣ�� //// 读取指定i节点信息。 // ���豸�϶�ȡ����ָ��i�ڵ���Ϣ��i�ڵ��̿飬Ȼ���Ƶ�ָ����i�ڵ�ṹ�С�
-Ϊ�� // 从设备上读取含有指定i节点信息的i节点盘块,然后复制到指定的i节点结构中。
+为了 // ȷ��i�ڵ����ڵ��豸����ţ���飩���������ȶ�ȡ��Ӧ�豸�ϵij����飬�Ի�ȡ // 确定i节点所在的设备逻辑块号(或缓冲块),必须首先读取相应设备上的超级块,以获取 // ���ڼ�������ŵ�ÿ��i�ڵ�����Ϣ INODES_PER_BLOCK�� �ڼ����i�ڵ����ڵ����� // 用于计算逻辑块号的每块i节点数信息 INODES_PER_BLOCK。 在计算出i节点所在的逻辑块 // �źͰѸ��������һ������С�Ȼ��ѻ��������Ӧλ�ô���i�ڵ����ݸ��Ƶ����� // 号后,就把该逻辑块读入一缓冲块中。然后把缓冲块中相应位置处的i节点内容复制到参数 // ָ����λ�ô��� // 指定的位置处。 297 static void read_inode(struct
@@ -3391,7 +3391,7 @@ lang=EN-US> int block; // ����������i�ڵ㣬��ȡ�ýڵ������豸�ij����顣 // 首先锁定该i节点,并取该节点所在设备的超级块。 303 &nb
panic("trying to read inode
without dev"); // ��i�ڵ����ڵ��豸����� = (������ + ������) + i�ڵ�λͼռ�õĿ��� + ����λ // 该i节点所在的设备逻辑块号 = (启动块 + 超级块) + i节点位图占用的块数 + 逻辑块位 // ͼռ�õĿ��� + (i�ڵ��-1)/ÿ�麬�е�i�ڵ�������Ȼi�ڵ�Ŵ�0��ʼ��ţ�����1 // 图占用的块数 + (i节点号-1)/每块含有的i节点数。虽然i节点号从0开始编号,但第1 // ��0��i�ڵ㲻�ã����Ҵ�����Ҳ�������Ӧ��0��i�ڵ�ṹ����˴��i�ڵ���̿�� // 个0号i节点不用,并且磁盘上也不保存对应的0号i节点结构。因此存放i节点的盘块的 // ��1���ϱ������i�ڵ������1--16��i�ڵ�ṹ������0--15�ġ�������������i�� // 第1块上保存的是i节点号是是1--16的i节点结构而不是0--15的。因此在上面计算i节 // ��Ŷ�Ӧ��i�ڵ�ṹ�����̿�ʱ��Ҫ��1������B =(i�ڵ��-1)/ÿ�麬��i�ڵ�ṹ���� // 点号对应的i节点结构所在盘块时需要减1,即:B =(i节点号-1)/每块含有i节点结构数。 // ���磬�ڵ��16��i�ڵ�ṹӦ����B=(16-1)/16
-= 0�Ŀ��ϡ� �������Ǵ��豸�϶�ȡ�� // 例如,节点号16的i节点结构应该在B=(16-1)/16
+= 0的块上。 这里我们从设备上读取该 // i�ڵ����ڵ����飬������ָ��i�ڵ����ݵ�inodeָ����ָλ�ô��� // i节点所在的逻辑块,并复制指定i节点内容到inode指针所指位置处。 306 block = 2 +
@@ -3462,10 +3462,10 @@ lang=EN-US> &nb
lang=EN-US>
[(inode->i_num-1)%INODES_PER_BLOCK]; // ����ͷŶ���Ļ���飬��������i�ڵ㡣���ڿ��豸�ļ�������Ҫ����i�ڵ���ļ���� // 最后释放读入的缓冲块,并解锁该i节点。对于块设备文件,还需要设置i节点的文件最大 // ����ֵ�� // 长度值。 313 S_ISBLK(inode->i_mode)) { 315
-int i = inode->i_zone[0]; // ���ڿ��豸�ļ���i_zone[0]�����豸�š� 316
@@ -3509,19 +3509,19 @@ lang=EN-US> } 323 //// ��i�ڵ���Ϣд�뻺�����С� //// 将i节点信息写入缓冲区中。 // �ú����Ѳ���ָ����i�ڵ�д�뻺������Ӧ�Ļ�����У���������ˢ��ʱ��д�����С�Ϊ�� // 该函数把参数指定的i节点写入缓冲区相应的缓冲块中,待缓冲区刷新时会写入盘中。为了 // ȷ��i�ڵ����ڵ��豸����ţ���飩���������ȶ�ȡ��Ӧ�豸�ϵij����飬�Ի�ȡ // 确定i节点所在的设备逻辑块号(或缓冲块),必须首先读取相应设备上的超级块,以获取 // ���ڼ�������ŵ�ÿ��i�ڵ�����Ϣ INODES_PER_BLOCK�� �ڼ����i�ڵ����ڵ����� // 用于计算逻辑块号的每块i节点数信息 INODES_PER_BLOCK。 在计算出i节点所在的逻辑块 // �źͰѸ��������һ������С�Ȼ���i�ڵ����ݸ��Ƶ���������Ӧλ�ô��� // 号后,就把该逻辑块读入一缓冲块中。然后把i节点内容复制到缓冲块的相应位置处。 324 static void write_inode(struct
@@ -3544,13 +3544,13 @@ lang=EN-US> int block; // ����������i�ڵ㣬�����i�ڵ�û�б��Ĺ����߸�i�ڵ���豸�ŵ����㣬������� // 首先锁定该i节点,如果该i节点没有被修改过或者该i节点的设备号等于零,则解锁该 // i�ڵ㣬���˳�������û�б��Ĺ���i�ڵ㣬�������뻺�����л��豸�е���ͬ�� Ȼ�� // i节点,并退出。对于没有被修改过的i节点,其内容与缓冲区中或设备中的相同。 然后 // ��ȡ��i�ڵ�ij����顣 // 获取该i节点的超级块。 330 &nb
panic("trying to write inode
without device"); // ��i�ڵ����ڵ��豸����� = (������ + ������) + i�ڵ�λͼռ�õĿ��� + ����λ // 该i节点所在的设备逻辑块号 = (启动块 + 超级块) + i节点位图占用的块数 + 逻辑块位 // ͼռ�õĿ��� + (i�ڵ��-1)/ÿ�麬�е�i�ڵ����� ���Ǵ��豸�϶�ȡ��i�ڵ����ڵ� // 图占用的块数 + (i节点号-1)/每块含有的i节点数。 我们从设备上读取该i节点所在的 // ���飬������i�ڵ���Ϣ���Ƶ������Ӧ��i�ڵ����λ�ô��� // 逻辑块,并将该i节点信息复制到逻辑块对应该i节点的项位置处。 337 block = 2 +
@@ -3620,11 +3620,11 @@ lang=EN-US> &nb
lang=EN-US>
*(struct d_inode *)inode; // Ȼ���û��������ı�־����i�ڵ������Ѿ��뻺�����е�һ�£�����ı�־���㡣Ȼ�� // 然后置缓冲区已修改标志,而i节点内容已经与缓冲区中的一致,因此修改标志置零。然后 // �ͷŸú���i�ڵ�Ļ���������������i�ڵ㡣 // 释放该含有i节点的缓冲区,并解锁该i节点。 344 bh->b_dirt=1; /* * super.c�����к��д�����������Ĵ��롣
+ * super.c程序中含有处理超级块表的代码。
*/ 10
-#include <linux/config.h> // �ں�����ͷ�ļ�������������Ժ�Ӳ�����ͣ�HD_TYPE����ѡ� 11
-#include <linux/sched.h> // ���ȳ���ͷ�ļ�������������ṹtask_struct������0�����ݣ�
-// ����һЩ�й��������������úͻ�ȡ��Ƕ��ʽ��ຯ������䡣 12
-#include <linux/kernel.h> // �ں�ͷ�ļ�������һЩ�ں˳��ú�����ԭ�ζ��塣 13
-#include <asm/system.h> // ϵͳͷ�ļ������������û���������/�ж��ŵȵ�Ƕ��ʽ���ꡣ 14 15
-#include <errno.h> // �����ͷ�ļ�������ϵͳ�и��ֳ����š� 16
-#include <sys/stat.h> // �ļ�״̬ͷ�ļ��������ļ����ļ�ϵͳ״̬�ṹstat{}�ͳ����� 17 // ��ָ���豸ִ�и��ٻ������豸�����ݵ�ͬ��������fs/buffer.c��59�У��� // 对指定设备执行高速缓冲与设备上数据的同步操作(fs/buffer.c,59行)。 18 int
sync_dev(int dev); // �ȴ�������kernel/chr_drv/tty_io.c��140�У��� // 等待击键(kernel/chr_drv/tty_io.c,140行)。 19
void wait_for_keypress(void); 21 /*
set_bit uses setb, as gas doesn't recognize setc */ /* set_bit()ʹ����setbָ���Ϊ��������gas����ʶ��ָ�� /* set_bit()使用了setb指令,因为汇编编译器gas不能识别指令setc */ //// ����ָ��λƫ�ƴ�����λ��ֵ�������ظ�ԭ����λֵ��Ӧ��ȡ��Ϊtest_bit()���������� //// 测试指定位偏移处比特位的值,并返回该原比特位值(应该取名为test_bit()更妥帖)。 // Ƕ��ʽ���ꡣ����bitnr�DZ���λƫ��ֵ��addr�Dz��Ա���λ��������ʼ��ַ�� // 嵌入式汇编宏。参数bitnr是比特位偏移值,addr是测试比特位操作的起始地址。 // %0 - ax(__res)��%1 - 0��%2 - bitnr��%3
+ // %0 - ax(__res),%1 - 0,%2 - bitnr,%3
- addr // ��23�ж�����һ���ֲ��Ĵ����������ñ�������������eax�Ĵ����У��Ա��ڸ�Ч���ʺ� // 第23行定义了一个局部寄存器变量。该变量将被保存在eax寄存器中,以便于高效访问和 // ��������24����ָ��bt ���ڶԱ���λ���в��ԣ�Bit Test��������ѵ�ַaddr��%3���� // 操作。第24行上指令bt 用于对比特位进行测试(Bit Test)。它会把地址addr(%3)和 // ����λƫ����bitnr��%2��ָ���ı���λ��ֵ�����λ��־CF �С� ָ��setb���ڸ��ݽ� // 比特位偏移量bitnr(%2)指定的比特位的值放入进位标志CF 中。 指令setb用于根据进 // λ��־CF���ò�����%al�����CF = 1��%al = 1������%al = 0�� // 位标志CF设置操作数%al。如果CF = 1则%al = 1,否则%al = 0。 22
#define set_bit(bitnr,addr) ({ \ 27
struct super_block super_block[NR_SUPER];
-// ������ṹ�����飨NR_SUPER = 8���� 28 /*
this is initialized in init/main.c */ /* ROOT_DEV����init/main.c�б���ʼ�� */ /* ROOT_DEV已在init/main.c中被初始化 */ 29 int
ROOT_DEV = 0;
-// ���ļ�ϵͳ�豸�š� 30 // ����3��������lock_super()��free_super()��wait_on_super()����������inode.c�� // 以下3个函数(lock_super()、free_super()和wait_on_super())的作用与inode.c文 // ����ͷ3��������������ͬ��ֻ����������Ķ����˳����顣 // 件中头3个函数的作用雷同,只是这里操作的对象换成了超级块。 //// ���������顣 //// 锁定超级块。 // ����������ѱ���������ǰ������Ϊ�����жϵĵȴ�״̬�������ӵ��ó�����ȴ��� // 如果超级块已被锁定,则将当前任务置为不可中断的等待状态,并添加到该超级块等待队 // ��s_wait�С�ֱ���ó������������ȷ�ػ��ѱ�����Ȼ����������� // 列s_wait中。直到该超级块解锁并明确地唤醒本任务。然后对其上锁。 31
static void lock_super(struct super_block * sb) 33
cli();
-// ���жϡ� 34
while (sb->s_lock)
-// ����ó������Ѿ���������˯�ߵȴ��� 35
sleep_on(&(sb->s_wait));
-// kernel/sched.c����199�� 36
sb->s_lock = 1;
-// ���ó������������������־���� 37
sti();
-// ���жϡ� 38 } 39 //// ��ָ������������� //// 对指定超级块解锁。 // ��λ�������������־������ȷ�ػ��ѵȴ��ڴ˳�����ȴ�����s_wait�ϵ����н��̡� // 复位超级块的锁定标志,并明确地唤醒等待在此超级块等待队列s_wait上的所有进程。 // ���ʹ��ulock_super�����������ܸ������� // 如果使用ulock_super这个名称则可能更妥帖。 40
static void free_super(struct super_block * sb) 43
sb->s_lock = 0;
-// ��λ������־�� 44
wake_up(&(sb->s_wait));
-// ���ѵȴ��ó�����Ľ��̡� 45
sti();
-// wake_up()��kernel/sched.c����188�С� 46 } 47 //// ˯�ߵȴ������������ //// 睡眠等待超级块解锁。 // ����������ѱ���������ǰ������Ϊ�����жϵĵȴ�״̬�������ӵ��ó�����ĵȴ��� // 如果超级块已被锁定,则将当前任务置为不可中断的等待状态,并添加到该超级块的等待队 // ��s_wait�С�ֱ���ó������������ȷ�ػ��ѱ����� // 列s_wait中。直到该超级块解锁并明确地唤醒本任务。 48
static void wait_on_super(struct super_block * sb) 51
while (sb->s_lock)
-// ����������Ѿ���������˯�ߵȴ��� 52
sleep_on(&(sb->s_wait)); 55 //// ȡָ���豸�ij����顣 //// 取指定设备的超级块。 // �ڳ�����������飩������ָ���豸dev�ij�����ṹ��Ϣ�����ҵ��س������ָ�룬 // 在超级块表(数组)中搜索指定设备dev的超级块结构信息。若找到则返回超级块的指针, // ���ؿ�ָ�롣 // 否则返回空指针。 56
struct super_block * get_super(int dev) 58
struct super_block * s; //
-s�dz��������ݽṹָ�롣 59 // �����жϲ��������豸����Ч�ԡ����豸��Ϊ0�ؿ�ָ�롣Ȼ����sָ�������� // 首先判断参数给出设备的有效性。若设备号为0则返回空指针。然后让s指向超级块数组 // ��ʼ������ʼ�����������������飬��Ѱ��ָ���豸dev�ij����顣 ��62���ϵ�ָ�븳 // 起始处,开始搜索整个超级块数组,以寻找指定设备dev的超级块。 第62行上的指针赋 // ֵ���"s
-= 0+super_block" ��ͬ�� "s = super_block"��"s = &super_block[0]"�� // 值语句"s
+= 0+super_block" 等同于 "s = super_block"、"s = &super_block[0]"。 60
if (!dev) // �����ǰ��������ָ���豸�ij����飬���ó�������豸���ֶ�ֵ�뺯������ָ������ͬ�� // 如果当前搜索项是指定设备的超级块,即该超级块的设备号字段值与函数参数指定的相同, // ���ȵȴ��ó�������������ѱ��������������Ļ������ڵȴ��ڼ䣬�ó��������п��ܱ� // 则先等待该超级块解锁(若已被其他进程上锁的话)。在等待期间,该超级块项有可能被 // �����豸ʹ�ã���˵ȴ�����֮�������ж�һ���Ƿ���ָ���豸�ij����飬������� // 其他设备使用,因此等待返回之后需再判断一次是否是指定设备的超级块,如果是则返回 // �ó������ָ�롣��������¶Գ���������������һ�飬��˴�ʱs������ָ������ // 该超级块的指针。否则就重新对超级块数组再搜索一遍,因此此时s需重又指向超级块数 // �鿪ʼ���� // 组开始处。 64
if (s->s_dev == dev) { 68
s = 0+super_block; // �����ǰ������ǣ�������һ����û���ҵ�ָ���ij����飬�ؿ�ָ�롣 // 如果当前搜索项不是,则检查下一项。如果没有找到指定的超级块,则返回空指针。 69
} else 73 //// �ͷţ��Żأ�ָ���豸�ij����顣 //// 释放(放回)指定设备的超级块。 // �ͷ��豸��ʹ�õij������������s_dev=0�������ͷŸ��豸i�ڵ�λͼ������λͼ�� // 释放设备所使用的超级块数组项(置s_dev=0),并释放该设备i节点位图和逻辑块位图所 // ռ�õĸ��ٻ���顣����������Ӧ���ļ�ϵͳ�Ǹ��ļ�ϵͳ��������ij��i�ڵ����Ѿ��� // 占用的高速缓冲块。如果超级块对应的文件系统是根文件系统,或者其某个i节点上已经安 // װ���������ļ�ϵͳ�������ͷŸó����顣 // 装有其他的文件系统,则不能释放该超级块。 74
void put_super(int dev) 78 // �����жϲ�������Ч�ԺͺϷ��ԡ����ָ���豸�Ǹ��ļ�ϵͳ�豸������ʾ������Ϣ����ϵ // 首先判断参数的有效性和合法性。如果指定设备是根文件系统设备,则显示警告信息“根系 // ͳ�̸ı��ˣ���������ս�ɡ��������ء�Ȼ���ڳ��������Ѱ��ָ���豸�ŵ��ļ�ϵͳ�� // 统盘改变了,准备生死决战吧”,并返回。然后在超级块表中寻找指定设备号的文件系统超 // ���顣����Ҳ���ָ���豸�ij����飬�ء����⣬����ó�����ָ�����ļ�ϵͳ����װ // 级块。如果找不到指定设备的超级块,则返回。另外,如果该超级块指明该文件系统所安装 // ����i�ڵ㻹û�б�������������ʾ������Ϣ�����ء����ļ�ϵͳж�أ�umount�������У� // 到的i节点还没有被处理过,则显示警告信息并返回。在文件系统卸载(umount)操作中, // s_imount���ȱ��ó�Null�Ժ�Ż���ñ��������μ���192�С� // s_imount会先被置成Null以后才会调用本函数,参见第192行。 79
if (dev == ROOT_DEV) { 88
} // Ȼ�����ҵ�ָ���豸�ij�����֮�������������ó����飬���øó������Ӧ���豸���ֶ� // 然后在找到指定设备的超级块之后,我们先锁定该超级块,再置该超级块对应的设备号字段 // s_dev Ϊ0��Ҳ���ͷŸ��豸�ϵ��ļ�ϵͳ�����顣Ȼ���ͷŸó�����ռ�õ������ں���Դ�� // s_dev 为0,也即释放该设备上的文件系统超级块。然后释放该超级块占用的其他内核资源, // ���ͷŸ��豸���ļ�ϵͳi�ڵ�λͼ������λͼ�ڻ���������ռ�õĻ���顣���泣���� // 即释放该设备上文件系统i节点位图和逻辑块位图在缓冲区中所占用的缓冲块。下面常数符 // ��I_MAP_SLOTS��Z_MAP_SLOTS������8�����ڷֱ�ָ��i�ڵ�λͼ������λͼռ�õĴ� // 号I_MAP_SLOTS和Z_MAP_SLOTS均等于8,用于分别指明i节点位图和逻辑块位图占用的磁 // ����������ע�⣬����Щ��������ݱ��Ĺ�������Ҫ��ͬ���������ܰѻ�����е����� // 盘逻辑块数。注意,若这些缓冲块内容被修改过,则需要作同步操作才能把缓冲块中的数据 // д���豸�С��������Ըó���������������ء� // 写入设备中。函数最后对该超级块解锁,并返回。 89
lock_super(sb); 90
sb->s_dev = 0;
-// �ó�������С� 91
for(i=0;i<I_MAP_SLOTS;i++) 98 //// ��ȡָ���豸�ij����顣 //// 读取指定设备的超级块。 // ���ָ���豸dev�ϵ��ļ�ϵͳ�������Ѿ��ڳ�������У���ֱ�ӷ��ظó��������ָ�롣 // 如果指定设备dev上的文件系统超级块已经在超级块表中,则直接返回该超级块项的指针。 // ����ʹ��豸dev�϶�ȡ�����鵽������У������Ƶ���������С������س�����ָ�롣 // 否则就从设备dev上读取超级块到缓冲块中,并复制到超级块表中。并返回超级块指针。 99
static struct super_block * int i,block;<
104 // �����жϲ�������Ч�ԡ����û��ָ���豸���ؿ�ָ�롣Ȼ������豸�Ƿ�ɸ��� // 首先判断参数的有效性。如果没有指明设备,则返回空指针。然后检查该设备是否可更换 // ����Ƭ��Ҳ���Ƿ��������豸��������������̣�����ٻ������йظ��豸�����л���� // 过盘片(也即是否是软盘设备)。如果更换过盘,则高速缓冲区有关该设备的所有缓冲块 // ��ʧЧ����Ҫ����ʧЧ���������ͷ�ԭ�����ص��ļ�ϵͳ�� // 均失效,需要进行失效处理,即释放原来加载的文件系统。 105 if (!dev) // ������豸�ij������Ѿ��ڳ�������У���ֱ�ӷ��ظó������ָ�롣���������ڳ��� // 如果该设备的超级块已经在超级块表中,则直接返回该超级块的指针。否则,首先在超级 // ���������ҳ�һ������(Ҳ���ֶ�s_dev=0����)����������Ѿ�ռ���ؿ�ָ�롣 // 块数组中找出一个空项(也即字段s_dev=0的项)。如果数组已经占满则返回空指针。 108 if (s = 115 } // �ڳ������������ҵ�����֮�ͽ��ó�����������ָ���豸dev�ϵ��ļ�ϵͳ�����Ƕ� // 在超级块数组中找到空项之后,就将该超级块项用于指定设备dev上的文件系统。于是对 // �ó�����ṹ�е��ڴ��ֶν��в��ֳ�ʼ�������� // 该超级块结构中的内存字段进行部分初始化处理。 116 s->s_dev = dev;
-// ����dev�豸�ϵ��ļ�ϵͳ�� 117 s->s_isup = s->s_rd_only =
121 s->s_dirt = 0; // Ȼ�������ó����飬�����豸�϶�ȡ��������Ϣ��bhָ��Ļ�����С�������λ�ڿ��豸 // 然后锁定该超级块,并从设备上读取超级块信息到bh指向的缓冲块中。超级块位于块设备 // �ĵ�2�����飨1�ſ飩�У�����1���������̿飩����������������ʧ�ܣ����ͷ��� // 的第2个逻辑块(1号块)中,(第1个是引导盘块)。如果读超级块操作失败,则释放上 // ��ѡ���ij����������е������s_dev=0����������������ؿ�ָ���˳�������ͽ��� // 面选定的超级块数组中的项(即置s_dev=0),并解锁该项,返回空指针退出。否则就将设 // ���϶�ȡ�ij�������Ϣ�ӻ�������������Ƶ�������������Ӧ��ṹ�С����ͷŴ�Ŷ�ȡ�� // 备上读取的超级块信息从缓冲块数据区复制到超级块数组相应项结构中。并释放存放读取信 // Ϣ�ĸ��ٻ���顣 // 息的高速缓冲块。 122 // �������Ǵ��豸dev�ϵõ����ļ�ϵͳ�ij����飬���ǿ�ʼ���������������Ч�Բ����� // 现在我们从设备dev上得到了文件系统的超级块,于是开始检查这个超级块的有效性并从设 // ���϶�ȡi�ڵ�λͼ������λͼ����Ϣ���������ȡ�ij�������ļ�ϵͳħ���ֶβ��ԣ� // 备上读取i节点位图和逻辑块位图等信息。如果所读取的超级块的文件系统魔数字段不对, // ˵���豸�ϲ�����ȷ���ļ�ϵͳ�����ͬ����һ�����ͷ�����ѡ���ij����������е���� // 说明设备上不是正确的文件系统,因此同上面一样,释放上面选定的超级块数组中的项,并 // ����������ؿ�ָ���˳������ڸð�Linux�ںˣ�ֻ֧��MINIX�ļ�ϵͳ1.0�汾����ħ // 解锁该项,返回空指针退出。对于该版Linux内核,只支持MINIX文件系统1.0版本,其魔 // ����0x137f�� // 数是0x137f。 131 if (s->s_magic
@@ -2462,23 +2462,23 @@ return NULL; 135 } // ���濪ʼ��ȡ�豸��i�ڵ�λͼ������λͼ���ݡ����ȳ�ʼ���ڴ泬����ṹ��λͼ�ռ䡣 // 下面开始读取设备上i节点位图和逻辑块位图数据。首先初始化内存超级块结构中位图空间。 // Ȼ����豸�϶�ȡi�ڵ�λͼ������λͼ��Ϣ��������ڳ������Ӧ�ֶ��С�i�ڵ�λͼ // 然后从设备上读取i节点位图和逻辑块位图信息,并存放在超级块对应字段中。i节点位图 // �������豸��2�ſ鿪ʼ�������У���ռ��s_imap_blocks���顣����λͼ��i�ڵ�λ // 保存在设备上2号块开始的逻辑块中,共占用s_imap_blocks个块。逻辑块位图在i节点位 // ͼ���ڿ�ĺ������У���ռ��s_zmap_blocks���顣 // 图所在块的后续块中,共占用s_zmap_blocks个块。 136 for (i=0;i<I_MAP_SLOTS;i++)
-// ��ʼ�������� 137
@@ -2497,8 +2497,8 @@ lang=EN-US> block=2; 141 for (i=0 ; i <
-s->s_imap_blocks ; i++) // ��ȡ�豸��i�ڵ�λͼ�� 142
@@ -2518,7 +2518,7 @@ break; 146 for (i=0 ; i <
-s->s_zmap_blocks ; i++) // ��ȡ�豸������λͼ�� 147
@@ -2536,12 +2536,12 @@ else // ���������λͼ����������λͼӦ��ռ�е���������˵���ļ�ϵͳλͼ��Ϣ�����⣬���� // 如果读出的位图块数不等于位图应该占有的逻辑块数,说明文件系统位图信息有问题,超级 // ���ʼ��ʧ�ܡ����ֻ���ͷ�ǰ�����벢ռ�õ�������Դ�����ͷ�i�ڵ�λͼ������λͼ // 块初始化失败。因此只能释放前面申请并占用的所有资源,即释放i节点位图和逻辑块位图 // ռ�õĸ��ٻ���顢�ͷ�����ѡ���ij���������������ó�����������ؿ�ָ���˳��� // 占用的高速缓冲块、释放上面选定的超级块数组项、解锁该超级块项,并返回空指针退出。 151 if (block !=
@@ -2550,7 +2550,7 @@ lang=EN-US> if (block !=
152
for(i=0;i<I_MAP_SLOTS;i++)
-// �ͷ�λͼռ�õĸ��ٻ���顣 153
@@ -2567,12 +2567,12 @@ lang=EN-US> &nb
156
s->s_dev=0;
-// �ͷ�ѡ���ij���������� 157
free_super(s);
-// ��������� 158
@@ -2581,18 +2581,18 @@ return NULL; 159 } // ����һ�гɹ������⣬���ڶ����������i�ڵ�ĺ�������������豸�����е�i�ڵ��Ѿ� // 否则一切成功。另外,由于对于申请空闲i节点的函数来讲,如果设备上所有的i节点已经 // ȫ��ʹ�ã�����Һ����᷵��0ֵ�����0��i�ڵ��Dz����õģ��������ォλͼ�е�1�� // 全被使用,则查找函数会返回0值。因此0号i节点是不能用的,所以这里将位图中第1块 // ����ͱ���λ����Ϊ1���Է�ֹ�ļ�ϵͳ����0��i�ڵ㡣ͬ���ĵ�����Ҳ������λͼ�� // 的最低比特位设置为1,以防止文件系统分配0号i节点。同样的道理,也将逻辑块位图的 // ���λ����Ϊ1������������ó����飬�����س�����ָ�롣 // 最低位设置为1。最后函数解锁该超级块,并返回超级块指针。 160
@@ -2615,16 +2615,16 @@ lang=EN-US> } 165 //// ж���ļ�ϵͳ��ϵͳ���ã��� //// 卸载文件系统(系统调用)。 // ����dev_name���ļ�ϵͳ�����豸���豸�ļ����� // 参数dev_name是文件系统所在设备的设备文件名。 // �ú������ȸ��ݲ��������Ŀ��豸�ļ�������豸�ţ�Ȼ��λ�ļ�ϵͳ�������е���Ӧ�� // 该函数首先根据参数给出的块设备文件名获得设备号,然后复位文件系统超级块中的相应字 // �Σ��ͷų������λͼռ�õĻ���飬���Ը��豸ִ�и��ٻ������豸�����ݵ�ͬ�������� // 段,释放超级块和位图占用的缓冲块,最后对该设备执行高速缓冲与设备上数据的同步操作。 // ��ж�ز����ɹ���0�����س����롣 // 若卸载操作成功则返回0,否则返回出错码。 166 int sys_umount(char *
@@ -2647,17 +2647,17 @@ lang=EN-US> int dev; 171 // ���ȸ����豸�ļ����ҵ���Ӧ��i�ڵ㣬��ȡ���е��豸�š��豸�ļ��������豸���豸�� // 首先根据设备文件名找到对应的i节点,并取其中的设备号。设备文件所定义设备的设备号 // �DZ�������i�ڵ��i_zone[0]�еġ� �μ�����namei.c������ϵͳ����sys_mknod()�Ĵ� // 是保存在其i节点的i_zone[0]中的。 参见后面namei.c程序中系统调用sys_mknod()的代 // ���445�С����⣬�����ļ�ϵͳ��Ҫ����ڿ��豸�ϣ����������ǿ��豸�ļ�����Ż� // 码第445行。另外,由于文件系统需要存放在块设备上,因此如果不是块设备文件,则放回 // �������i�ڵ�dev_i�����س����롣 // 刚申请的i节点dev_i,返回出错码。 172 if (!(inode=S_ISBLK(inode->i_mode)) { 176
iput(inode);
-// fs/inode.c����150�� 177
@@ -2687,12 +2687,12 @@ return -ENOTBLK; 178 } // OK����������Ϊ�˵õ��豸�Ŷ�ȡ�õ�i�ڵ������������ʹ�����������Żظ��豸�ļ� // OK,现在上面为了得到设备号而取得的i节点已完成了它的使命,因此这里放回该设备文件 // ��i�ڵ㡣�������������һ��ж�ظ��ļ�ϵͳ�������Ƿ����㡣����豸���Ǹ��ļ�ϵͳ�� // 的i节点。接着我们来检查一下卸载该文件系统的条件是否满足。如果设备上是根文件系统, // ���ܱ�ж�أ�����æ�����š� // 则不能被卸载,返回忙出错号。 179 ROOT_DEV) // ����ڳ��������û���ҵ����豸���ļ�ϵͳ�ij����飬�������ҵ����Ǹ��豸���ļ�ϵͳ // 如果在超级块表中没有找到该设备上文件系统的超级块,或者已找到但是该设备上文件系统 // û�а�װ�����س����롣�����������ָ���ı���װ����i�ڵ㲢û����λ�䰲װ��־ // 没有安装过,则返回出错码。如果超级块所指明的被安装到的i节点并没有置位其安装标志 // i_mount������ʾ������Ϣ�� Ȼ�����һ��i�ڵ���������Ƿ��н�����ʹ�ø��豸�ϵ��� // i_mount,则显示警告信息。 然后查找一下i节点表,看看是否有进程在使用该设备上的文 // �����������æ�����롣 // 件,如果有则返回忙出错码。 182 if (!(sb= // ���ڸ��豸���ļ�ϵͳ��ж���������õ����㣬������ǿ��Կ�ʼʵʩ������ж�ز����ˡ� // 现在该设备上文件系统的卸载条件均得到满足,因此我们可以开始实施真正的卸载操作了。 // ���ȸ�λ����װ����i�ڵ�İ�װ��־���ͷŸ�i�ڵ㡣Ȼ���ó������б���װi�ڵ��ֶ� // 首先复位被安装到的i节点的安装标志,释放该i节点。然后置超级块中被安装i节点字段 // Ϊ�գ����Ż��豸�ļ�ϵͳ�ĸ�i�ڵ㣬�����ó������б���װϵͳ��i�ڵ�ָ��Ϊ�ա� // 为空,并放回设备文件系统的根i节点,接着置超级块中被安装系统根i节点指针为空。 189
@@ -2776,10 +2776,10 @@ style='color:blue'>iput(sb->s_isup); // ��������ͷŸ��豸�ϵij������Լ�λͼռ�õĸ��ٻ���飬���Ը��豸ִ�и��ٻ������� // 最后我们释放该设备上的超级块以及位图占用的高速缓冲块,并对该设备执行高速缓冲与设 // �������ݵ�ͬ��������Ȼ��0��ж�سɹ����� // 备上数据的同步操作。然后返回0(卸载成功)。 194 } 198 //// ��װ�ļ�ϵͳ��ϵͳ���ã��� //// 安装文件系统(系统调用)。 // ����dev_name���豸�ļ�����dir_name�ǰ�װ����Ŀ¼����rw_flag����װ�ļ�ϵͳ�Ŀ� // 参数dev_name是设备文件名,dir_name是安装到的目录名,rw_flag被安装文件系统的可 // ��д��־���������صĵط�������һ��Ŀ¼�������Ҷ�Ӧ��i�ڵ�û�б���������ռ�á� // 读写标志。将被加载的地方必须是一个目录名,并且对应的i节点没有被其他程序占用。 // �������ɹ���0�����س����š� // 若操作成功则返回0,否则返回出错号。 199 int sys_mount(char *
@@ -2830,14 +2830,14 @@ lang=EN-US> int dev; 204 // ���ȸ����豸�ļ����ҵ���Ӧ��i�ڵ㣬��ȡ�����е��豸�š����ڿ������豸�ļ����豸 // 首先根据设备文件名找到对应的i节点,以取得其中的设备号。对于块特殊设备文件,设备 // ������i�ڵ��i_zone[0]�С����⣬�����ļ�ϵͳ�����ڿ��豸�У����������ǿ��豸 // 号在其i节点的i_zone[0]中。另外,由于文件系统必须在块设备中,因此如果不是块设备 // �ļ�����Żظ�ȡ�õ�i�ڵ�dev_i�����س����롣 // 文件,则放回刚取得的i节点dev_i,返回出错码。 205 if (!(dev_i=EPERM; 211 } // OK����������Ϊ�˵õ��豸�Ŷ�ȡ�õ�i�ڵ�dev_i�����������ʹ�����������Żظ��� // OK,现在上面为了得到设备号而取得的i节点dev_i已完成了它的使命,因此这里放回该设 // ���ļ���i�ڵ㡣�������������һ���ļ�ϵͳ��װ����Ŀ¼���Ƿ���Ч�����Ǹ��ݸ����� // 备文件的i节点。接着我们来检查一下文件系统安装到的目录名是否有效。于是根据给定的 // Ŀ¼�ļ����ҵ���Ӧ��i�ڵ� dir_i�� �����i�ڵ�����ü�����Ϊ1�������������ã��� // 目录文件名找到对应的i节点 dir_i。 如果该i节点的引用计数不为1(仅在这里引用), // ���߸�i�ڵ�Ľڵ���Ǹ��ļ�ϵͳ�Ľڵ��1����Żظ�i�ڵ㷵�س����롣���⣬��� // 或者该i节点的节点号是根文件系统的节点号1,则放回该i节点返回出错码。另外,如果 // �ýڵ㲻��һ��Ŀ¼�ļ��ڵ㣬��Ҳ�Żظ�i�ڵ㣬���س����롣��Ϊ�ļ�ϵͳֻ�ܰ�װ�� // 该节点不是一个目录文件节点,则也放回该i节点,返回出错码。因为文件系统只能安装在 // һ��Ŀ¼���ϡ� // 一个目录名上。 212 } 219 if (!S_ISDIR(dir_i->i_mode)) {
-// ��װ����Ҫ��һ��Ŀ¼���� 220
@@ -2927,12 +2927,12 @@ return -EPERM; 222 } // ���ڰ�װ��Ҳ�����ϣ����ǿ�ʼ��ȡҪ��װ�ļ�ϵͳ�ij�������Ϣ����������������ʧ // 现在安装点也检查完毕,我们开始读取要安装文件系统的超级块信息。如果读超级块操作失 // �ܣ���Żظð�װ��i�ڵ�dir_i�����س����롣һ���ļ�ϵͳ�ij���������ȴӳ������ // 败,则放回该安装点i节点dir_i并返回出错码。一个文件系统的超级块会首先从超级块表 // �н���������������ڳ�������оʹ��豸�϶�ȡ�� // 中进行搜索,如果不在超级块表中就从设备上读取。 223 if (!(sb=EBUSY; 226 } // �ڵõ����ļ�ϵͳ������֮�����Ƕ����Ƚ��м��һ���������Ҫ����װ���ļ�ϵͳ�Ѿ� // 在得到了文件系统超级块之后,我们对它先进行检测一番。如果将要被安装的文件系统已经 // ��װ�������ط�����Żظ�i�ڵ㣬���س����롣�����Ҫ��װ����i�ڵ��Ѿ���װ���ļ� // 安装在其他地方,则放回该i节点,返回出错码。如果将要安装到的i节点已经安装了文件 // ϵͳ����װ��־�Ѿ���λ������Żظ�i�ڵ㣬Ҳ���س����롣 // 系统(安装标志已经置位),则放回该i节点,也返回出错码。 227 if
@@ -2987,11 +2987,11 @@ return -EPERM; 234 } // ������ñ���װ�ļ�ϵͳ������ġ�����װ��i�ڵ㡱�ֶ�ָ��װ����Ŀ¼����i�ڵ㡣 // 最后设置被安装文件系统超级块的“被安装到i节点”字段指向安装到的目录名的i节点。 // �����ð�װλ��i�ڵ�İ�װ��־�ͽڵ����ı�־��Ȼ��0����װ�ɹ����� // 并设置安装位置i节点的安装标志和节点已修改标志。然后返回0(安装成功)。 235
@@ -3002,13 +3002,13 @@ lang=EN-US> dir_i->i_mount=1;
237 dir_i->i_dirt=1;/*
-NOTE! we don't iput(dir_i) */ /*ע��!����û�� /*注意!这里没用iput(dir_i)*/ 238 return
0; /* we do that in umount */
-/* �⽫��umount�ڲ��� */ 239 } 240 //// ��װ���ļ�ϵͳ�� //// 安装根文件系统。 // �ú�������ϵͳ��ʼ��������һ���֡��������ȳ�ʼ���ļ�������file_table[]�ͳ������ // 该函数属于系统初始化操作的一部分。函数首先初始化文件表数组file_table[]和超级块表 // �����飩��Ȼ���ȡ���ļ�ϵͳ�����飬��ȡ���ļ�ϵͳ��i�ڵ㡣 ���ͳ�Ʋ���ʾ������ // (数组),然后读取根文件系统超级块,并取得文件系统根i节点。 最后统计并显示出根文 // ��ϵͳ�ϵĿ�����Դ�����п����Ϳ���i�ڵ������� �ú�������ϵͳ�������г�ʼ������ʱ // 件系统上的可用资源(空闲块数和空闲i节点数)。 该函数会在系统开机进行初始化设置时 // ��sys_setup()�����ã�blk_drv/hd.c��157�У��� // (sys_setup())调用(blk_drv/hd.c,157行)。 241 void mount_root(void) 246 // ������i�ڵ�ṹ����32�ֽڣ������ͣ�������ж����ڷ�ֹ�Ĵ���ʱ���ֲ�һ������� // 若磁盘i节点结构不是32字节,则出错停机。该判断用于防止修改代码时出现不一致情况。 247 if (32 != sizeof
@@ -3062,20 +3062,20 @@ lang=EN-US> if (32 != sizeof
lang=EN-US>
panic("bad i-node size"); // ���ȳ�ʼ���ļ������飨��64���ϵͳͬʱֻ�ܴ�64���ļ����ͳ�����������ォ�� // 首先初始化文件表数组(共64项,即系统同时只能打开64个文件)和超级块表。这里将所 // ���ļ��ṹ�е����ü�������Ϊ0����ʾ���У������ѳ�������и���ṹ���豸�ֶγ�ʼ // 有文件结构中的引用计数设置为0(表示空闲),并把超级块表中各项结构的设备字段初始 // ��Ϊ0��Ҳ��ʾ���У���������ļ�ϵͳ�����豸�����̵Ļ�������ʾ��������ļ�ϵͳ�̣� // 化为0(也表示空闲)。如果根文件系统所在设备是软盘的话,就提示“插入根文件系统盘, // �����س����������ȴ������� // 并按回车键”,并等待按键。 249 for(i=0;i<NR_FILE;i++)
-// ��ʼ���ļ����� 250
@@ -3085,7 +3085,7 @@ lang=EN-US> &nb
lang=EN-US> if (MAJOR(ROOT_DEV)
== 2) {
-// ��ʾ������ļ�ϵͳ�̡� 252
@@ -3108,7 +3108,7 @@ style='color:blue'>super_block[NR_SUPER
256 p->s_dev
= 0;
-// ��ʼ����������� 257
@@ -3121,12 +3121,12 @@ p->s_wait = NULL; 259 } // �������ϡ����⡱�ij�ʼ������֮�����ǿ�ʼ��װ���ļ�ϵͳ�����ǴӸ��豸�϶�ȡ�ļ� // 做好以上“份外”的初始化工作之后,我们开始安装根文件系统。于是从根设备上读取文件 // ϵͳ�����飬��ȡ���ļ�ϵͳ�ĸ�i�ڵ㣨1�Žڵ㣩���ڴ�i�ڵ���е�ָ�롣������� // 系统超级块,并取得文件系统的根i节点(1号节点)在内存i节点表中的指针。如果读根 // �豸�ϳ�����ʧ�ܻ�ȡ���ڵ�ʧ�ܣ�����ʾ��Ϣ��ͣ���� // 设备上超级块失败或取根节点失败,则都显示信息并停机。 260 if (!(p=); 263
panic("Unable to read root
i-node"); // �������ǶԳ������i�ڵ�������á��Ѹ�i�ڵ����ô�������3�Ρ���Ϊ����266���� // 现在我们对超级块和根i节点进行设置。把根i节点引用次数递增3次。因为下面266行上 // Ҳ�����˸�i�ڵ㡣���⣬iget() ������i�ڵ����ü����ѱ�����Ϊ1��Ȼ���øó������ // 也引用了该i节点。另外,iget() 函数中i节点引用计数已被设置为1。然后置该超级块的 // ����װ�ļ�ϵͳi�ڵ�ͱ���װ��i�ڵ��ֶ�Ϊ��i�ڵ㡣�����õ�ǰ���̵ĵ�ǰ����Ŀ¼ // 被安装文件系统i节点和被安装到i节点字段为该i节点。再设置当前进程的当前工作目录 // ��Ŀ¼i�ڵ㡣��ʱ��ǰ������1�Ž��̣�init���̣��� // 和根目录i节点。此时当前进程是1号进程(init进程)。 264
@@ -3169,7 +3169,7 @@ lang=EN-US>1�Ž��̣�init���̣��
it is logically used 4 times, not 1 */
-/* ע�⣡�����Ͻ������ѱ�������4�Σ�������1��注意!从逻辑上讲,它已被引用了4次,而不是1次 */ 265current->pwd = mi; // Ȼ�����ǶԸ��ļ�ϵͳ�ϵ���Դ��ͳ�ƹ�����ͳ�Ƹ��豸�Ͽ��п����Ϳ���i�ڵ��������� // 然后我们对根文件系统上的资源作统计工作。统计该设备上空闲块数和空闲i节点数。首先 // ��i���ڳ������б������豸����������Ȼ���������λͼ����Ӧ����λ��ռ�����ͳ // 令i等于超级块中表明的设备逻辑块总数。然后根据逻辑块位图中相应比特位的占用情况统 // �Ƴ����п���������꺯��set_bit()ֻ���ڲ��Ա���λ���������ñ���λ��"i&8191" ���� // 计出空闲块数。这里宏函数set_bit()只是在测试比特位,而非设置比特位。"i&8191" 用于 // ȡ��i�ڵ���ڵ�ǰλͼ���ж�Ӧ�ı���λƫ��ֵ��"i>>13" �ǽ�i����8192��Ҳ����һ�� // 取得i节点号在当前位图块中对应的比特位偏移值。"i>>13" 是将i除以8192,也即除一个 // ���̿�����ı���λ���� // 磁盘块包含的比特位数。 268 set_bit(i&8191,p->s_zmap[i>
lang=EN-US>
free++; // ����ʾ���豸�Ͽ���������/��������֮��������ͳ���豸�Ͽ���i�ڵ����������� // 在显示过设备上空闲逻辑块数/逻辑块总数之后。我们再统计设备上空闲i节点数。首先令i // ���ڳ������б������豸��i�ڵ�����+1����1�ǽ�0�ڵ�Ҳͳ�ƽ�ȥ��Ȼ�����i�ڵ�λ // 等于超级块中表明的设备上i节点总数+1。加1是将0节点也统计进去。然后根据i节点位 // ͼ����Ӧ����λ��ռ��������������i�ڵ������������ʾ�豸�Ͽ��ÿ���i�ڵ����� // 图中相应比特位的占用情况计算出空闲i节点数。最后再显示设备上可用空闲i节点数和i // �ڵ������� // 节点总数。 273
-
10 11
-#include <linux/sched.h> // ���ȳ���ͷ�ļ�������������ṹtask_struct������0�����ݵȡ� 12
-#include <linux/kernel.h> // �ں�ͷ�ļ�������һЩ�ں˳��ú�����ԭ�ζ��塣 13
-#include <asm/segment.h> // �β���ͷ�ļ����������йضμĴ���������Ƕ��ʽ��ຯ���� 14 15
-#include <string.h> // �ַ���ͷ�ļ�����Ҫ������һЩ�й��ַ���������Ƕ�뺯���� 16
-#include <fcntl.h> // �ļ�����ͷ�ļ����ļ������������IJ������Ƴ������ŵĶ��塣 17
-#include <errno.h> // �����ͷ�ļ�������ϵͳ�и��ֳ����š� 18
-#include <const.h> // ��������ͷ�ļ���Ŀǰ������i�ڵ���i_mode�ֶεĸ���־λ�� 19
-#include <sys/stat.h> // �ļ�״̬ͷ�ļ��������ļ����ļ�ϵͳ״̬�ṹstat{}�ͳ����� 20 // ���ļ������Ҷ�Ӧi�ڵ���ڲ������� // 由文件名查找对应i节点的内部函数。 21
static struct m_inode * 23 // ��������Ҳ����ʽ�Ƿ��������һ������ʹ�÷�����������������һ����ʵ�������������� // 下面宏中右侧表达式是访问数组的一种特殊使用方法。它基于这样的一个事实,即用数组名和 // �����±�����ʾ�����������a[b]����ֵ��ͬ��ʹ��������ָ�루��ַ�����ϸ���ƫ�Ƶ�ַ // 数组下标所表示的数组项(例如a[b])的值等同于使用数组首指针(地址)加上该项偏移地址 // ����ʽ��ֵ *(a + b)��ͬʱ��֪��a[b]Ҳ���Ա�ʾ��b[a]����ʽ����˶����ַ���������ʽ // 的形式的值 *(a + b),同时可知项a[b]也可以表示成b[a]的形式。因此对于字符数组项形式 // Ϊ "LoveYou"[2]������2["LoveYou"]���͵�ͬ��*("LoveYou"
-+ 2)�����⣬�ַ���"LoveYou" // 为 "LoveYou"[2](或者2["LoveYou"])就等同于*("LoveYou"
++ 2)。另外,字符串"LoveYou" // ���ڴ��б��洢��λ�þ������ַ�����������"LoveYou"[2]��ֵ���Ǹ��ַ���������ֵΪ2 // 在内存中被存储的位置就是其地址,因此数组项"LoveYou"[2]的值就是该字符串中索引值为2 // ���ַ�"v"����Ӧ��ASCII��ֵ0x76�����ð˽��Ʊ�ʾ����0166����C�����У��ַ�Ҳ������ // 的字符"v"所对应的ASCII码值0x76,或用八进制表示就是0166。在C语言中,字符也可以用 // ��ASCII��ֵ����ʾ�����������ַ���ASCII��ֵǰ���һ����б�ܡ������ַ� "v"���Ա�ʾ // 其ASCII码值来表示,方法是在字符的ASCII码值前面加一个反斜杠。例如字符 "v"可以表示 // ��"\x76"����"\166"����˶��ڲ�����ʾ���ַ�������ASCII��ֵΪ0x00--0x1f�Ŀ����ַ��� // 成"\x76"或者"\166"。因此对于不可显示的字符(例如ASCII码值为0x00--0x1f的控制字符) // �Ϳ�����ASCII��ֵ����ʾ�� // 就可用其ASCII码值来表示。 // // �����Ƿ���ģʽ�ꡣx��ͷ�ļ�include/fcntl.h�е�7�п�ʼ������ļ����ʣ�����־�� // 下面是访问模式宏。x是头文件include/fcntl.h中第7行开始定义的文件访问(打开)标志。 // ���������ļ����ʱ�־x��ֵ������˫�����ж�Ӧ����ֵ��˫��������4���˽�����ֵ��ʵ // 这个宏根据文件访问标志x的值来索引双引号中对应的数值。双引号中有4个八进制数值(实 // �ʱ�ʾ4�������ַ�����"\004\002\006\377"���ֱ��ʾ����д��ִ�е�Ȩ��Ϊ:
-r��w��rw // 际表示4个控制字符):"\004\002\006\377",分别表示读、写和执行的权限为:
+r、w、rw // ��wxrwxrwx�����ҷֱ��Ӧx������ֵ0--3�� ���磬���xΪ2����ú귵�ذ˽���ֵ006�� // 和wxrwxrwx,并且分别对应x的索引值0--3。 例如,如果x为2,则该宏返回八进制值006, // ��ʾ�ɶ���д��rw�������⣬����O_ACCMODE = 00003��������ֵx�������롣 // 表示可读可写(rw)。另外,其中O_ACCMODE = 00003,是索引值x的屏蔽码。 24
#define ACC_MODE( /* * ��������ļ������� > NAME_LEN�����ַ����ص����ͽ����涨��ע�͵��� * 如果想让文件名长度 > NAME_LEN个的字符被截掉,就将下面定义注释掉。 */ 32
#define MAY_EXEC 1
-// ��ִ��(�ɽ���)�� 33
#define MAY_WRITE 2
-// ��� 34
#define MAY_READ 4
-// �ɶ��� 35 * * �ú������ڼ��һ���ļ��Ķ�/д/ִ��Ȩ�ޡ��Ҳ�֪���Ƿ�ֻ����euid�� * 该函数用于检测一个文件的读/写/执行权限。我不知道是否只需检查euid, * ������Ҫ���euid��uid���ߣ�������������ġ� * 还是需要检查euid和uid两者,不过这很容易修改。 */ //// ����ļ���������Ȩ�ޡ� //// 检测文件访问许可权限。 // ������inode
-- �ļ���i�ڵ�ָ�룻mask - �������������롣 // 参数:inode
+- 文件的i节点指针;mask - 访问属性屏蔽码。 // ���أ��������ɷ���1������0�� // 返回:访问许可返回1,否则返回0。 43
static int permission(struct m_inode * inode,int mask) 45
int mode = inode->i_mode; //
-�ļ��������ԡ� 46 47 /*
special case: not even root can read/write a deleted file */ /* �����������ʹ�dz����û���root��Ҳ���ܶ�/дһ���ѱ�ɾ�����ļ�
+ /* 特殊情况:即使是超级用户(root)也不能读/写一个已被删除的文件
*/ // ���i�ڵ��ж�Ӧ���豸������i�ڵ�����Ӽ���ֵ����0����ʾ���ļ��ѱ�ɾ�����ء� // 如果i节点有对应的设备,但该i节点的链接计数值等于0,表示该文件已被删除,则返回。 // ����������̵���Ч�û�id��euid����i�ڵ���û�id��ͬ����ȡ�ļ������ķ���Ȩ�ޡ� // 否则,如果进程的有效用户id(euid)与i节点的用户id相同,则取文件宿主的访问权限。 // ����������̵���Ч��id��egid����i�ڵ����id��ͬ����ȡ���û��ķ���Ȩ�ޡ� // 否则,如果进程的有效组id(egid)与i节点的组id相同,则取组用户的访问权限。 48
if (inode->i_dev && !inode->i_nlinks) // ����ж������ȡ�ĵķ���Ȩ������������ͬ�������dz����û�����1������0�� // 最后判断如果所取的的访问权限与屏蔽码相同,或者是超级用户,则返回1,否则返回0。 54
if (((mode & mask & 0007) == mask) || suser()) /* * ok�����Dz���ʹ��strncmp�ַ����ȽϺ�������Ϊ���Ʋ������ǵ����ݿռ� * ok,我们不能使用strncmp字符串比较函数,因为名称不在我们的数据空间 * �������ں˿ռ䣩�� �������ֻ��ʹ��
-match()�����ⲻ��match()ͬ�� * (不在内核空间)。 因而我们只能使用
+match()。问题不大,match()同样 * Ҳ����һЩ�����IJ��ԡ� * 也处理一些完整的测试。 * * ע�⣡��strncmp��ͬ����match()�ɹ�ʱ����1��ʧ��ʱ����0�� * 注意!与strncmp不同的是match()成功时返回1,失败时返回0。 */ //// ָ�������ַ����ȽϺ����� //// 指定长度字符串比较函数。 // ������len
-- �Ƚϵ��ַ������ȣ�name - �ļ���ָ�룻de - Ŀ¼��ṹ�� // 参数:len
+- 比较的字符串长度;name - 文件名指针;de - 目录项结构。 // ���أ���ͬ����1����ͬ����0�� // 返回:相同返回1,不同返回0。 // ��68���϶�����һ���ֲ��Ĵ�������same���ñ�������������eax�Ĵ����У��Ա��ڸ�Ч // 第68行上定义了一个局部寄存器变量same。该变量将被保存在eax寄存器中,以便于高效 // ���ʡ� // 访问。 66
static int match(int len,const char *
@@ -2262,31 +2262,31 @@ register int same __asm__("ax"); 69 // �����жϺ�����������Ч�ԡ����Ŀ¼��ָ��գ�����Ŀ¼��i�ڵ����0������Ҫ�Ƚϵ� // 首先判断函数参数的有效性。如果目录项指针空,或者目录项i节点等于0,或者要比较的 // �ַ������ȳ����ļ������ȣ���0����ƥ�䣩������Ƚϵij���len����0����Ŀ¼�� // 字符串长度超过文件名长度,则返回0(不匹配)。如果比较的长度len等于0并且目录项 // ���ļ����ĵ�1���ַ��� '.'������ֻ����ôһ���ַ�����ô���Ǿ���Ϊ����ͬ�ģ���˷� // 中文件名的第1个字符是 '.',并且只有这么一个字符,那么我们就认为是相同的,因此返 // ��1��ƥ�䣩�����Ҫ�Ƚϵij���lenС��NAME_LEN������Ŀ¼�����ļ������ȳ���len�� // 回1(匹配)。如果要比较的长度len小于NAME_LEN,但是目录项中文件名长度超过len, // ��Ҳ����0����ƥ�䣩�� // 则也返回0(不匹配)。 // ��75���϶�Ŀ¼�����ļ��������Ƿ�
-len ���жϷ����Ǽ�� name[len] �Ƿ�ΪNULL�� // 第75行上对目录项中文件名长度是否超过
+len 的判断方法是检测 name[len] 是否为NULL。 // �����ȳ���len����name[len]������һ������NULL����ͨ�ַ��������ڳ���Ϊlen���ַ� // 若长度超过len,则name[len]处就是一个不是NULL的普通字符。而对于长度为len的字符 // ��name���ַ�name[len]��Ӧ����NULL�� // 串name,字符name[len]就应该是NULL。 70
if (!de || !de->inode || len > NAME_LEN)
-/* "" ���� "." ������ ---> �������ܴ����� "/usr/lib//libc.a"
-������·���� */ 73
if (!len && (de->name[0]=='.') && (de->name[1]=='\0')) 76
return 0; // Ȼ��ʹ��Ƕ���������п��ٱȽϲ������������û����ݿռ䣨fs�Σ�ִ���ַ����ıȽ� // 然后使用嵌入汇编语句进行快速比较操作。它会在用户数据空间(fs段)执行字符串的比较 // ������%0
-- eax���ȽϽ��same����%1 - eax��eax��ֵ0����%2 - esi������ָ�룩�� // 操作。%0
+- eax(比较结果same);%1 - eax(eax初值0);%2 - esi(名字指针); // %3 - edi��Ŀ¼����ָ�룩��%4 - ecx(�Ƚϵ��ֽڳ���ֵlen)�� // %3 - edi(目录项名指针);%4 - ecx(比较的字节长度值len)。 77
__asm__("cld\n\t"
-// �巽���־λ�� 78
-"fs ; repe ; cmpsb\n\t" // �û��ռ�ִ��ѭ���Ƚ�[esi++]��[edi++]������ 79
"setz %%al"
- // ���ȽϽ��һ����zf=0������al=1��same=eax���� 80
:"=a" (same) 83
return same;
-// ���رȽϽ���� 84 } * * ��ָ��Ŀ¼��Ѱ��һ��������ƥ���Ŀ¼�����һ�������ҵ�Ŀ¼��ĸ��� * 在指定目录中寻找一个与名字匹配的目录项。返回一个含有找到目录项的高速 * ������Լ�Ŀ¼�������Ϊһ������ - res_dir�����ú���������ȡĿ¼�� * 缓冲块以及目录项本身(作为一个参数 - res_dir)。该函数并不读取目录项 * ��i�ڵ� - �����Ҫ�Ļ����Լ������� * 的i节点 - 如果需要的话则自己操作。 * * ������'..'Ŀ¼�����ڲ����ڼ�Ҳ��Լ�����������ֱ��� - �����Խ * 由于有'..'目录项,因此在操作期间也会对几种特殊情况分别处理 - 比如横越 * һ��α��Ŀ¼�Լ���װ�㡣 * 一个伪根目录以及安装点。 */ //// ����ָ��Ŀ¼���ļ�����Ŀ¼� //// 查找指定目录和文件名的目录项。 // ������*dir
-- ָ��Ŀ¼i�ڵ��ָ�룻name - �ļ�����namelen - �ļ������ȣ� // 参数:*dir
+- 指定目录i节点的指针;name - 文件名;namelen - 文件名长度; // �ú�����ָ��Ŀ¼�����ݣ��ļ���������ָ���ļ�����Ŀ¼�����ָ���ļ�����'..'�� // 该函数在指定目录的数据(文件)中搜索指定文件名的目录项。并对指定文件名是'..'的 // ������ݵ�ǰ���е�������ý�������������ں�����������ָ���ָ������ã���� // 情况根据当前进行的相关设置进行特殊处理。关于函数参数传递指针的指针的作用,请参 // ��linux/sched.c��151��ǰ��ע�͡� // 见linux/sched.c第151行前的注释。 // ���أ��ɹ��������ٻ�����ָ�룬����*res_dir�����ص�Ŀ¼��ṹָ�롣ʧ���� // 返回:成功则函数高速缓冲区指针,并在*res_dir处返回的目录项结构指针。失败则返回 // ��ָ��NULL�� // 空指针NULL。 97
static struct buffer_head * super_block * sb; 105 // ͬ����������һ����Ҳ��Ҫ�Ժ�����������Ч�Խ����жϺ���֤�����������ǰ���30�� // 同样,本函数一上来也需要对函数参数的有效性进行判断和验证。如果我们在前面第30行 // �����˷��ų���NO_TRUNCATE����ô����ļ������ȳ������NAME_LEN�����账���� // 定义了符号常数NO_TRUNCATE,那么如果文件名长度超过最大长度NAME_LEN,则不予处理。 // ���û�ж����NO_TRUNCATE����ô���ļ������ȳ������NAME_LENʱ�ض�֮�� // 如果没有定义过NO_TRUNCATE,那么在文件名长度超过最大长度NAME_LEN时截短之。 106 #ifdef NO_TRUNCATE // ���ȼ��㱾Ŀ¼��Ŀ¼������entries�� Ŀ¼i�ڵ� i_size�ֶ��к��б�Ŀ¼���������� // 首先计算本目录中目录项项数entries。 目录i节点 i_size字段中含有本目录包含的数据 // ���ȣ���������һ��Ŀ¼��ij��ȣ�16�ֽڣ����ɵõ���Ŀ¼��Ŀ¼������Ȼ���ÿշ��� // 长度,因此其除以一个目录项的长度(16字节)即可得到该目录中目录项数。然后置空返回 // Ŀ¼��ṹָ�롣 // 目录项结构指针。 113 entries =
@@ -2513,36 +2513,36 @@ lang=EN-US> entries =
lang=EN-US> *res_dir = NULL; // ���������Ƕ�Ŀ¼���ļ�����'..'���������������������ǰ����ָ���ĸ�i�ڵ���� // 接下来我们对目录项文件名是'..'的情况进行特殊处理。如果当前进程指定的根i节点就是 // ��������ָ����Ŀ¼����˵�����ڱ�������˵�����Ŀ¼��������α��Ŀ¼��������ֻ�ܷ� // 函数参数指定的目录,则说明对于本进程来说,这个目录就是它的伪根目录,即进程只能访 // �ʸ�Ŀ¼�е�������ܺ��˵��丸Ŀ¼��ȥ��Ҳ�����ڸý��̱�Ŀ¼����ͬ���ļ�ϵͳ�ĸ� // 问该目录中的项而不能后退到其父目录中去。也即对于该进程本目录就如同是文件系统的根 // Ŀ¼�����������Ҫ���ļ�����Ϊ'.'�� // 目录。因此我们需要将文件名修改为'.'。 // ���������Ŀ¼��i�ڵ�ŵ���ROOT_INO��1�ţ��Ļ���˵��ȷʵ���ļ�ϵͳ�ĸ�i�ڵ㡣 // 否则,如果该目录的i节点号等于ROOT_INO(1号)的话,说明确实是文件系统的根i节点。 // ��ȡ�ļ�ϵͳ�ij����顣�������װ����i�ڵ���ڣ����ȷŻ�ԭi�ڵ㣬Ȼ��Ա���װ�� // 则取文件系统的超级块。如果被安装到的i节点存在,则先放回原i节点,然后对被安装到 // ��i�ڵ���д���������������*dirָ��ñ���װ����i�ڵ㣻���Ҹ�i�ڵ����������1�� // 的i节点进行处理。于是我们让*dir指向该被安装到的i节点;并且该i节点的引用数加1。 // ���������������������ĵؽ����ˡ�͵������������ // 即针对这种情况,我们悄悄地进行了“偷梁换柱”工程:) 115 /* check for '..', as we might have to do some
"magic" for it */ /* ���Ŀ¼�� '..'����Ϊ���ǿ�����Ҫ������������ */ /* 检查目录项 '..',因为我们可能需要对其进行特殊处理 */ 116 if (namelen==2
@@ -2554,8 +2554,8 @@ lang=EN-US> if (namelen==2
lang=EN-US> /* '..' in a pseudo-root results in a faked '.' (just change
namelen) */ /* α���е� '..'
-��ͬһ���� '.'��ֻ��ı����ֳ��ȣ� */ /* 伪根中的 '..'
+如同一个假 '.'(只需改变名字长度) */ 118
@@ -2577,11 +2577,11 @@ for the mounted /* ��һ����װ���ϵ� '..' ������Ŀ¼����������װ�ļ�ϵͳ��Ŀ¼i�ڵ��ϡ�ע�⣡ /* 在一个安装点上的 '..' 将导致目录交换到被安装文件系统的目录i节点上。注意! ��������������mounted��־����������ܹ��Żظ���Ŀ¼ */ 由于我们设置了mounted标志,因而我们能够放回该新目录 */ 123 sb= } // �������ǿ�ʼ��������������ָ���ļ�����Ŀ¼����ʲô�ط������������Ҫ��ȡĿ¼���� // 现在我们开始正常操作,查找指定文件名的目录项在什么地方。因此我们需要读取目录的数 // �ݣ���ȡ��Ŀ¼i�ڵ��Ӧ���豸�������е����ݿ飨���飩��Ϣ����Щ����Ŀ�ű� // 据,即取出目录i节点对应块设备数据区中的数据块(逻辑块)信息。这些逻辑块的块号保 // ����i�ڵ�ṹ��
-i_zone[9]�����С�������ȡ���е�1����š����Ŀ¼i�ڵ�ָ��ĵ� // 存在i节点结构的
+i_zone[9]数组中。我们先取其中第1个块号。如果目录i节点指向的第 // һ��ֱ�Ӵ��̿��Ϊ0����˵����Ŀ¼��Ȼ�������ݣ��ⲻ���������Ƿ���NULL�˳������� // 一个直接磁盘块号为0,则说明该目录竟然不含数据,这不正常。于是返回NULL退出。否则 // ���Ǿʹӽڵ������豸��ȡָ����Ŀ¼�����ݿ顣��Ȼ��������ɹ�����Ҳ����NULL�˳��� // 我们就从节点所在设备读取指定的目录项数据块。当然,如果不成功,则也返回NULL退出。 131 if (!(block =
@@ -2649,14 +2649,14 @@ return NULL; // ��ʱ���Ǿ��������ȡ��Ŀ¼i�ڵ����ݿ�������ƥ��ָ���ļ�����Ŀ¼�������deָ // 此时我们就在这个读取的目录i节点数据块中搜索匹配指定文件名的目录项。首先让de指 // ����е����ݿ鲿�֣����ڲ�����Ŀ¼��Ŀ¼�����������£�ѭ��ִ������������i�� // 向缓冲块中的数据块部分,并在不超过目录中目录项数的条件下,循环执行搜索。其中i是 // Ŀ¼�е�Ŀ¼�������ţ���ѭ����ʼʱ��ʼ��Ϊ0�� // 目录中的目录项索引号,在循环开始时初始化为0。 135 i = 0; // �����ǰĿ¼�����ݿ��Ѿ������꣬��û���ҵ�ƥ���Ŀ¼����ͷŵ�ǰĿ¼�����ݿ顣 // 如果当前目录项数据块已经搜索完,还没有找到匹配的目录项,则释放当前目录项数据块。 // �ٶ���Ŀ¼����һ�����顣�����Ϊ�գ���ֻҪ��û��������Ŀ¼�е�����Ŀ¼��� // 再读入目录的下一个逻辑块。若这块为空,则只要还没有搜索完目录中的所有目录项,就 // �����ÿ飬������Ŀ¼����һ���顣���ÿ鲻�գ�����
-de ָ������ݿ飬Ȼ�������� // 跳过该块,继续读目录的下一逻辑块。若该块不空,就让
+de 指向该数据块,然后在其中 // ��������������141����i/DIR_ENTRIES_PER_BLOCK�ɵõ���ǰ������Ŀ¼������Ŀ¼�� // 继续搜索。其中141行上i/DIR_ENTRIES_PER_BLOCK可得到当前搜索的目录项所在目录文 // ���еĿ�ţ���bmap()������inode.c����142�У���ɼ�������豸�϶�Ӧ������š� // 件中的块号,而bmap()函数(inode.c,第142行)则可计算出在设备上对应的逻辑块号。 138
@@ -2724,11 +2724,11 @@ de = (struct dir_entry *) bh->b_data;<
lang=EN-US>
} // ����ҵ�ƥ���Ŀ¼��Ļ����ظ�Ŀ¼��ṹָ��de��Ŀ¼��i�ڵ�ָ��*dir�� // 如果找到匹配的目录项的话,则返回该目录项结构指针de和该目录项i节点指针*dir以 // ����Ŀ¼�����ݿ�ָ��bh�����˳����������������Ŀ¼�����ݿ��бȽ���һ��Ŀ¼� // 及该目录项数据块指针bh,并退出函数。否则继续在目录项数据块中比较下一个目录项。 148
@@ -2757,10 +2757,10 @@ i++; 154 } // ���ָ��Ŀ¼�е�����Ŀ¼��������û���ҵ���Ӧ��Ŀ¼����ͷ�Ŀ¼������ // 如果指定目录中的所有目录项都搜索完后,还没有找到相应的目录项,则释放目录的数据 // �飬���NULL��ʧ�ܣ��� // 块,最后返回NULL(失败)。 155 */ * add_entry() * ʹ����find_entry()ͬ���ķ�������ָ��Ŀ¼������һָ���ļ�����Ŀ * 使用与find_entry()同样的方法,往指定目录中添加一指定文件名的目 * ¼����ʧ����NULL�� * 录项。如果失败则返回NULL。 * * ע�⣡��'de'��ָ��Ŀ¼��ṹָ�룩��i�ڵ㲿�ֱ�����Ϊ0 - ��� * 注意!!'de'(指定目录项结构指针)的i节点部分被设置为0 - 这表 * ʾ�ڵ��øú�������Ŀ¼����������Ϣ֮�䲻��ȥ˯�ߡ�
-��Ϊ���˯�ߣ� * 示在调用该函数和往目录项中添加信息之间不能去睡眠。
+因为如果睡眠, * ��ô������(����)���ܻ�ʹ���˸�Ŀ¼� * 那么其他人(进程)可能会使用了该目录项。 */ //// ����ָ����Ŀ¼���ļ�������Ŀ¼� //// 根据指定的目录和文件名添加目录项。 // ������dir
-- ָ��Ŀ¼��i�ڵ㣻name - �ļ�����namelen - �ļ������ȣ� // 参数:dir
+- 指定目录的i节点;name - 文件名;namelen - 文件名长度; // ���أ����ٻ�����ָ�룻res_dir - ���ص�Ŀ¼��ṹָ�룻 // 返回:高速缓冲区指针;res_dir - 返回的目录项结构指针; 169 static struct buffer_head * dir_entry * de; 175 // ͬ����������һ����Ҳ��Ҫ�Ժ�����������Ч�Խ����жϺ���֤�����������ǰ���30�� // 同样,本函数一上来也需要对函数参数的有效性进行判断和验证。如果我们在前面第30行 // �����˷��ų���NO_TRUNCATE����ô����ļ������ȳ������NAME_LEN�����账���� // 定义了符号常数NO_TRUNCATE,那么如果文件名长度超过最大长度NAME_LEN,则不予处理。 // ���û�ж����NO_TRUNCATE����ô���ļ������ȳ������NAME_LENʱ�ض�֮�� // 如果没有定义过NO_TRUNCATE,那么在文件名长度超过最大长度NAME_LEN时截短之。 176 *res_dir = NULL;
-// ���ڷ���Ŀ¼��ṹָ�롣 177 #ifdef NO_TRUNCATE 183 #endif // �������ǿ�ʼ��������ָ��Ŀ¼������һ��ָ���ļ�����Ŀ¼����������Ҫ�ȶ�ȡĿ¼ // 现在我们开始操作,向指定目录中添加一个指定文件名的目录项。因此我们需要先读取目录 // �����ݣ���ȡ��Ŀ¼i�ڵ��Ӧ���豸�������е����ݿ飨���飩��Ϣ����Щ����Ŀ� // 的数据,即取出目录i节点对应块设备数据区中的数据块(逻辑块)信息。这些逻辑块的块 // �ű�����i�ڵ�ṹ��
-i_zone[9]�����С�������ȡ���е�1����š����Ŀ¼i�ڵ�ָ�� // 号保存在i节点结构的
+i_zone[9]数组中。我们先取其中第1个块号。如果目录i节点指向 // �ĵ�һ��ֱ�Ӵ��̿��Ϊ0����˵����Ŀ¼��Ȼ�������ݣ��ⲻ���������Ƿ���NULL�˳��� // 的第一个直接磁盘块号为0,则说明该目录竟然不含数据,这不正常。于是返回NULL退出。 // �������Ǿʹӽڵ������豸��ȡָ����Ŀ¼�����ݿ顣��Ȼ��������ɹ�����Ҳ���� // 否则我们就从节点所在设备读取指定的目录项数据块。当然,如果不成功,则也返回NULL // �˳������⣬��������ṩ���ļ������ȵ���0����Ҳ����NULL�˳��� // 退出。另外,如果参数提供的文件名长度等于0,则也返回NULL退出。 184 if (!namelen) // ��ʱ���Ǿ������Ŀ¼i�ڵ����ݿ���ѭ���������δʹ�õĿ�Ŀ¼�������Ŀ¼��ṹ // 此时我们就在这个目录i节点数据块中循环查找最后未使用的空目录项。首先让目录项结构 // ָ��deָ����е����ݿ鲿�֣�����һ��Ŀ¼�������i��Ŀ¼�е�Ŀ¼�������ţ� // 指针de指向缓冲块中的数据块部分,即第一个目录项处。其中i是目录中的目录项索引号, // ��ѭ����ʼʱ��ʼ��Ϊ0�� // 在循环开始时初始化为0。 190 i = 0; 192 while (1) { // �����ǰĿ¼�����ݿ��Ѿ�������ϣ�����û���ҵ���Ҫ�Ŀ�Ŀ¼����ͷŵ�ǰĿ¼���� // 如果当前目录项数据块已经搜索完毕,但还没有找到需要的空目录项,则释放当前目录项数 // �ݿ飬�ٶ���Ŀ¼����һ�����顣�����Ӧ�����鲻���ھʹ���һ�顣����ȡ���� // 据块,再读入目录的下一个逻辑块。如果对应的逻辑块不存在就创建一块。若读取或创建操 // ��ʧ���ؿա�����˴ζ�ȡ�Ĵ����������ݷ��صĻ����ָ��Ϊ�գ�˵��������� // 作失败则返回空。如果此次读取的磁盘逻辑块数据返回的缓冲块指针为空,说明这块逻辑块 // ��������Ϊ�����ڶ��´����Ŀտ飬���Ŀ¼������ֵ����һ�������������ɵ�Ŀ¼���� // 可能是因为不存在而新创建的空块,则把目录项索引值加上一块逻辑块所能容纳的目录项数 // DIR_ENTRIES_PER_BLOCK�����������ÿ鲢��������������˵���¶���Ŀ�����Ŀ¼�����ݣ� // DIR_ENTRIES_PER_BLOCK,用以跳过该块并继续搜索。否则说明新读入的块上有目录项数据, // ������Ŀ¼��ṹָ��deָ��ÿ�Ļ�������ݲ��֣�Ȼ�������м�������������196�� // 于是让目录项结构指针de指向该块的缓冲块数据部分,然后在其中继续搜索。其中196行 // �ϵ� i/DIR_ENTRIES_PER_BLOCK
-�ɼ���õ���ǰ������Ŀ¼��i ����Ŀ¼�ļ��еĿ�ţ� // 上的 i/DIR_ENTRIES_PER_BLOCK
+可计算得到当前搜索的目录项i 所在目录文件中的块号, // ��create_block()������inode.c����147�У���ɶ�ȡ�������豸�϶�Ӧ�����顣 // 而create_block()函数(inode.c,第147行)则可读取或创建出在设备上对应的逻辑块。 193
@@ -3018,7 +3018,7 @@ return NULL; 199
if (!(bh = bread(dir->i_dev,block)))
-{ // �����������ÿ������ 200
@@ -3040,19 +3040,19 @@ de = (struct dir_entry *) bh->b_data;<
lang=EN-US>
} // �����ǰ��������Ŀ¼�����i����Ŀ¼�ṹ��С���ij���ֵ�Ѿ������˸�Ŀ¼i�ڵ���Ϣ // 如果当前所操作的目录项序号i乘上目录结构大小所的长度值已经超过了该目录i节点信息 // ��ָ����Ŀ¼���ݳ���ֵ i_size ����˵������Ŀ¼�ļ�������û������ɾ���ļ����µĿ� // 所指出的目录数据长度值 i_size ,则说明整个目录文件数据中没有由于删除文件留下的空 // Ŀ¼��������ֻ�ܰ���Ҫ���ӵ���Ŀ¼��ӵ�Ŀ¼�ļ����ݵ�ĩ�˴������ǶԸô�Ŀ // 目录项,因此我们只能把需要添加的新目录项附加到目录文件数据的末端处。于是对该处目 // ¼��������ã��ø�Ŀ¼���i�ڵ�ָ��Ϊ�գ��������¸�Ŀ¼�ļ��ij���ֵ������һ��Ŀ // 录项进行设置(置该目录项的i节点指针为空),并更新该目录文件的长度值(加上一个目 // ¼��ij��ȣ���Ȼ������Ŀ¼��i�ڵ����ı�־���ٸ��¸�Ŀ¼�ĸı�ʱ��Ϊ��ǰʱ�䡣 // 录项的长度),然后设置目录的i节点已修改标志,再更新该目录的改变时间为当前时间。 205
@@ -3079,14 +3079,14 @@ dir->i_ctime = CURRENT_TIME; // ����ǰ������Ŀ¼�� de ��i�ڵ�Ϊ�գ����ʾ�ҵ�һ����δʹ�õĿ���Ŀ¼��������ӵ� // 若当前搜索的目录项 de 的i节点为空,则表示找到一个还未使用的空闲目录项或是添加的 // ��Ŀ¼����Ǹ���Ŀ¼����ʱ��Ϊ��ǰʱ�䣬�����û������������ļ�������Ŀ¼��� // 新目录项。于是更新目录的修改时间为当前时间,并从用户数据区复制文件名到该目录项的 // �ļ����ֶΣ��ú��б�Ŀ¼�����Ӧ���ٻ�������ı�־�����ظ�Ŀ¼���ָ���Լ��ø� // 文件名字段,置含有本目录项的相应高速缓冲块已修改标志。返回该目录项的指针以及该高 // �ٻ�����ָ�룬�˳��� // 速缓冲块的指针,退出。 211
@@ -3122,7 +3122,7 @@ lang=EN-US> &nb
219
-de++; // �����Ŀ¼���Ѿ���ʹ�ã�����������һ��Ŀ¼� 220
@@ -3131,11 +3131,11 @@ i++; 221 } // ������ִ�в��������Ҳ����Linus��д��δ���ʱ���ȸ���������find_entry()���� // 本函数执行不到这里。这也许是Linus在写这段代码时,先复制了上面find_entry()函数 // �Ĵ��룬�����ijɱ�������J�� // 的代码,而后修改成本函数的J。 222 } 225 //// ���ҷ������ӵ�i�ڵ㡣 //// 查找符号链接的i节点。 // ������dir
-- Ŀ¼i�ڵ㣻inode - Ŀ¼��i�ڵ㡣 // 参数:dir
+- 目录i节点;inode - 目录项i节点。 // ���أ����ط������ӵ��ļ���i�ڵ�ָ�롣��������NULL�� // 返回:返回符号链接到文件的i节点指针。出错返回NULL。 226 static struct m_inode * { 228 unsigned short fs;
-// ������ʱ����fs�μĴ���ֵ�� 229 struct buffer_head * bh; 230 // �����жϺ�����������Ч�ԡ����û�и���Ŀ¼i�ڵ㣬���Ǿ�ʹ�ý�������ṹ�����õ� // 首先判断函数参数的有效性。如果没有给出目录i节点,我们就使用进程任务结构中设置的 // ��i�ڵ㣬������������1�����û�и���Ŀ¼��i�ڵ㣬��Ż�Ŀ¼i�ڵ��NULL�� // 根i节点,并把链接数增1。如果没有给出目录项i节点,则放回目录i节点后返回NULL。 // ���ָ��Ŀ¼���һ���������ӣ���ֱ�ӷ���Ŀ¼���Ӧ��i�ڵ�inode�� // 如果指定目录项不是一个符号链接,就直接返回目录项对应的i节点inode。 231 if (!dir) { 242 } // Ȼ��ȡfs�μĴ���ֵ��fsͨ��������ָ���������ݶε�ѡ���0x17�����fsû��ָ���û� // 然后取fs段寄存器值。fs通常保存着指向任务数据段的选择符0x17。如果fs没有指向用户 // ���ݶΣ����߸�����Ŀ¼��i�ڵ��1��ֱ�ӿ��ŵ���0�������Ƕ�ȡ��1��ֱ�ӿ������ // 数据段,或者给出的目录项i节点第1个直接块块号等于0,或者是读取第1个直接块出错, // ��Ż�dir��inode����i�ڵ㲢����NULL�˳�������˵������fs��ָ���û����ݶΡ����� // 则放回dir和inode两个i节点并返回NULL退出。否则说明现在fs正指向用户数据段、并且 // �����Ѿ��ɹ��ض�ȡ�������������Ŀ¼����ļ����ݣ������ļ������Ѿ���
-bh ָ��Ļ��� // 我们已经成功地读取了这个符号链接目录项的文件内容,并且文件内容已经在
+bh 指向的缓冲 // ���������С�ʵ���ϣ����������������н�����һ������ָ����ļ�·�����ַ����� // 块数据区中。实际上,这个缓冲块数据区中仅包含一个链接指向的文件路径名字符串。 243 __asm__("mov
@@ -3278,22 +3278,22 @@ return NULL; 249 } // ��ʱ�����Ѿ�����Ҫ��������Ŀ¼���i�ڵ��ˣ����ǰ����Żء���������һ�����⣬�Ǿ� // 此时我们已经不需要符号链接目录项的i节点了,于是把它放回。现在碰到一个问题,那就 // ���ں˺����������û����ݶ��Ǵ�����û����ݿռ��еģ���ʹ����
-fs �μĴ��������û� // 是内核函数处理的用户数据都是存放在用户数据空间中的,并使用了
+fs 段寄存器来从用户 // �ռ䴫�����ݵ��ں˿ռ��С���������Ҫ����������ȴ���ں˿ռ��С����Ϊ����ȷ�ش��� // 空间传递数据到内核空间中。而这里需要处理的数据却在内核空间中。因此为了正确地处理 // λ���ں��е��û����ݣ�������Ҫ��fs�μĴ�����ʱָ���ں˿ռ䣬����fs =0x10������ // 位于内核中的用户数据,我们需要让fs段寄存器临时指向内核空间,即让fs =0x10。并在 // ���ú�����������ٻָ�ԭfs��ֵ������ͷ���Ӧ����飬������ _namei()�����õ��ķ� // 调用函数处理完后再恢复原fs的值。最后释放相应缓冲块,并返回 _namei()解析得到的符 // ������ָ����ļ�i�ڵ㡣 // 号链接指向的文件i节点。 250 * * �ú������ݸ�����·��������������ֱ���ﵽ��˵�Ŀ¼�� * 该函数根据给出的路径名进行搜索,直到达到最顶端的目录。 * ���ʧ����NULL�� * 如果失败则返回NULL。 */ //// ��ָ��Ŀ¼��ʼ��Ѱָ��·������Ŀ¼�����ļ�������i�ڵ㡣 //// 从指定目录开始搜寻指定路径名的目录(或文件名)的i节点。 // ������pathname
-- ·������inode - ָ����ʼĿ¼��i�ڵ㡣 // 参数:pathname
+- 路径名;inode - 指定起始目录的i节点。 // ���أ�Ŀ¼���ļ���i�ڵ�ָ�롣ʧ��ʱ����NULL�� // 返回:目录或文件的i节点指针。失败时返回NULL。 264 static struct m_inode * m_inode * dir; 272 // �����жϲ�����Ч�ԡ����������ָ��Ŀ¼��i�ڵ�ָ��inodeΪ�գ���ʹ�õ�ǰ���̵ĵ� // 首先判断参数有效性。如果给出的指定目录的i节点指针inode为空,则使用当前进程的当 // ǰ����Ŀ¼i�ڵ㡣����û�ָ��·�����ĵ�1���ַ���'/'����˵��·�����Ǿ���·������ // 前工作目录i节点。如果用户指定路径名的第1个字符是'/',则说明路径名是绝对路径名。 // ��Ӧ�ôӵ�ǰ��������ṹ�����õĸ�����α����i�ڵ㿪ʼ����������������Ҫ�ȷŻز� // 则应该从当前进程任务结构中设置的根(或伪根)i节点开始操作。于是我们需要先放回参 // ��ָ���Ļ����趨��Ŀ¼i�ڵ㣬��ȡ�ý���ʹ�õĸ�i�ڵ㡣Ȼ��Ѹ�i�ڵ�����ü��� // 数指定的或者设定的目录i节点,并取得进程使用的根i节点。然后把该i节点的引用计数 // ��1����ɾ��·�����ĵ�1���ַ� '/'�������Ϳ��Ա�֤��ǰ����ֻ�������趨�ĸ�i�ڵ� // 加1,并删除路径名的第1个字符 '/'。这样就可以保证当前进程只能以其设定的根i节点 // ��Ϊ��������㡣 // 作为搜索的起点。 273 if (!inode) { 274
inode = current->pwd;
-// ���̵ĵ�ǰ����Ŀ¼i�ڵ㡣 275
@@ -3440,12 +3440,12 @@ style='color:blue'>get_fs_byte(pathname))=='/') { 278
iput(inode);
-// �Ż�ԭi�ڵ㡣 279
inode = current->root;
-// Ϊ����ָ���ĸ�i�ڵ㡣 280
@@ -3458,23 +3458,23 @@ inode->i_count++; 282 } // Ȼ�����·�����еĸ���Ŀ¼�����ֺ��ļ�������ѭ����������ѭ�����������У�������Ҫ // 然后针对路径名中的各个目录名部分和文件名进行循环处理。在循环处理过程中,我们先要 // �Ե�ǰ���ڴ�����Ŀ¼�����ֵ� i�ڵ������Ч���жϣ����Ұѱ���thisname ָ��ǰ�� // 对当前正在处理的目录名部分的 i节点进行有效性判断,并且把变量thisname 指向当前正 // �ڴ�����Ŀ¼�����֡������i�ڵ������ǰ������Ŀ¼�����ֲ���Ŀ¼���ͣ�����û�п� // 在处理的目录名部分。如果该i节点表明当前处理的目录名部分不是目录类型,或者没有可 // �����Ŀ¼�ķ������ɣ���Żظ�i�ڵ㣬������NULL�˳��� ��Ȼ�ڸս���ѭ��ʱ����ǰ // 进入该目录的访问许可,则放回该i节点,并返回NULL退出。 当然在刚进入循环时,当前 // Ŀ¼��i�ڵ�inode���ǽ��̸�i�ڵ�����ǵ�ǰ����Ŀ¼��i�ڵ㣬�����Dz���ָ����ij // 目录的i节点inode就是进程根i节点或者是当前工作目录的i节点,或者是参数指定的某 // ��������ʼĿ¼��i�ڵ㡣 // 个搜索起始目录的i节点。 283 while (1) { // ÿ��ѭ�����Ǵ���·������һ��Ŀ¼�������ļ��������֡������ÿ��ѭ�������Ƕ�Ҫ��· // 每次循环我们处理路径名中一个目录名(或文件名)部分。因此在每次循环中我们都要从路 // �����ַ����з����һ��Ŀ¼�������ļ������������Ǵӵ�ǰ·����ָ��
-pathname ��ʼ�� // 径名字符串中分离出一个目录名(或文件名)。方法是从当前路径名指针
+pathname 开始处 // ��������ַ���ֱ���ַ���һ����β����NULL��������һ��'/'�ַ�����ʱ���� namelen �� // 搜索检测字符,直到字符是一个结尾符(NULL)或者是一个'/'字符。此时变量 namelen 正 // ���ǵ�ǰ����Ŀ¼�����ֵij��ȣ������� thisname ��ָ���Ŀ¼�����ֵĿ�ʼ������ʱ�� // 好是当前处理目录名部分的长度,而变量 thisname 正指向该目录名部分的开始处。此时如 // ���ַ��ǽ�β��NULL��������Ѿ�������·����ĩβ�����ѵ������ָ��Ŀ¼�����ļ����� // 果字符是结尾符NULL,则表明已经搜索到路径名末尾,并已到达最后指定目录名或文件名, // �ظ�i�ڵ�ָ���˳��� // 则返回该i节点指针退出。 // ע�⣡���·���������һ������Ҳ��һ��Ŀ¼�����������û�м���
-'/'�ַ��������� // 注意!如果路径名中最后一个名称也是一个目录名,但其后面没有加上
+'/'字符,则函数不 // �᷵�ظ����Ŀ¼����i�ڵ㣡���磺����·����/usr/src/linux���ú�����ֻ����src/Ŀ // 会返回该最后目录名的i节点!例如:对于路径名/usr/src/linux,该函数将只返回src/目 // ¼����i�ڵ㡣 // 录名的i节点。 289
@@ -3543,22 +3543,22 @@ if (!c) // �ڵõ���ǰĿ¼�����֣����ļ����������ǵ��ò���Ŀ¼���find_entry()�ڵ�ǰ�� // 在得到当前目录名部分(或文件名)后,我们调用查找目录项函数find_entry()在当前处 // ����Ŀ¼��Ѱ��ָ�����Ƶ�Ŀ¼����û���ҵ�����Żظ�i�ڵ㣬������NULL�˳��� // 理的目录中寻找指定名称的目录项。如果没有找到,则放回该i节点,并返回NULL退出。 // Ȼ�����ҵ���Ŀ¼����ȡ����i�ڵ��inr���豸��idev���ͷŰ�����Ŀ¼��ĸ��ٻ��� // 然后在找到的目录项中取出其i节点号inr和设备号idev,释放包含该目录项的高速缓冲 // �鲢�Żظ�i�ڵ㡣
-Ȼ��ȡ�ڵ��inr��i�ڵ�inode�����Ը�Ŀ¼��Ϊ��ǰĿ¼����ѭ // 块并放回该i节点。
+然后取节点号inr的i节点inode,并以该目录项为当前目录继续循 // ������·�����е���һĿ¼�����֣����ļ������������ǰ������Ŀ¼����һ���������� // 环处理路径名中的下一目录名部分(或文件名)。如果当前处理的目录项是一个符号链接 // ������ʹ��follow_link()�Ϳ��Եõ���ָ���Ŀ¼������i�ڵ㡣 // 名,则使用follow_link()就可以得到其指向的目录项名的i节点。 293
@@ -3580,7 +3580,7 @@ lang=EN-US> &nb
297
inr = de->inode;
-// ��ǰĿ¼�����ֵ�i�ڵ�š� 298
@@ -3593,7 +3593,7 @@ dir = inode; 300
if (!(inode = iget(dir->i_dev,inr)))
-{ // ȡi�ڵ����ݡ� 301
@@ -3648,23 +3648,23 @@ lang=EN-US> */ * * dir_namei()��������ָ��Ŀ¼����i�ڵ�ָ�룬�Լ������ * dir_namei()函数返回指定目录名的i节点指针,以及在最顶层 * Ŀ¼�����ơ� * 目录的名称。 */ // ������pathname
-- Ŀ¼·������namelen - ·�������ȣ�name - ���ص����Ŀ¼���� // 参数:pathname
+- 目录路径名;namelen - 路径名长度;name - 返回的最顶层目录名。 // base - ������ʼĿ¼��i�ڵ㡣 // base - 搜索起始目录的i节点。 // ���أ�ָ��Ŀ¼�����Ŀ¼��i�ڵ�ָ������Ŀ¼���Ƽ����ȡ�����ʱ����NULL�� // 返回:指定目录名最顶层目录的i节点指针和最顶层目录名称及长度。出错时返回NULL。 // ע�⣡��������Ŀ¼����ָ·���������ĩ�˵�Ŀ¼�� // 注意!!这里“最顶层目录”是指路径名中最靠近末端的目录。 315 static struct m_inode * m_inode * dir; 321 // ����ȡ��ָ��·�������Ŀ¼��i�ڵ㡣Ȼ���·����pathname����������⣬������ // 首先取得指定路径名最顶层目录的i节点。然后对路径名pathname进行搜索检测,查出最后 // һ��'/'�ַ�����������ַ����������䳤�ȣ����ҷ������Ŀ¼��i�ڵ�ָ�롣ע�⣡�� // 一个'/'字符后面的名字字符串,计算其长度,并且返回最顶层目录的i节点指针。注意!如 // ��·�������һ���ַ���б���ַ�'/'����ô���ص�Ŀ¼��Ϊ�գ����ҳ���Ϊ0�������ص� // 果路径名最后一个字符是斜杠字符'/',那么返回的目录名为空,并且长度为0。但返回的i // �ڵ�ָ����Ȼָ�����һ��'/'�ַ�ǰĿ¼����i�ڵ㡣�μ���289���ϵġ�ע�⡱˵���� // 节点指针仍然指向最后一个'/'字符前目录名的i节点。参见第289行上的“注意”说明。 322 if (!(dir = get_dir(pathname,base)))
-// base��ָ������ʼĿ¼i�ڵ㡣 323
@@ -3746,18 +3746,18 @@ lang=EN-US> } 332 //// ȡָ��·������i�ڵ��ڲ������� //// 取指定路径名的i节点内部函数。 // ������pathname
-- ·������base - �������Ŀ¼i�ڵ㣻follow_links - �Ƿ���� // 参数:pathname
+- 路径名;base - 搜索起点目录i节点;follow_links - 是否跟随 // �������ӵı�־��1 - ��Ҫ��0����Ҫ�� // 符号链接的标志,1 - 需要,0不需要。 // ���أ���Ӧ��i�ڵ㡣 // 返回:对应的i节点。 333 struct m_inode * dir_entry * de; 341 // ���Ȳ���ָ��·���������Ŀ¼��Ŀ¼�����õ���i�ڵ㡣�������ڣ���NULL�˳��� // 首先查找指定路径名中最顶层目录的目录名并得到其i节点。若不存在,则返回NULL退出。 // ������ص�������ֵij�����0�����ʾ��·������һ��Ŀ¼��Ϊ���һ����˵���� // 如果返回的最顶层名字的长度是0,则表示该路径名以一个目录名为最后一项。因此说明我 // ���Ѿ��ҵ���ӦĿ¼��i�ڵ㣬����ֱ�ӷ��ظ�i�ڵ��˳���������ص����ֳ��Ȳ���0�� // 们已经找到对应目录的i节点,可以直接返回该i节点退出。如果返回的名字长度不是0, // ��������ָ������ʼĿ¼base���ٴε���dir_namei()��������������Ŀ¼���������ݷ��� // 则我们以指定的起始目录base,再次调用dir_namei()函数来搜索顶层目录名,并根据返回 // ����Ϣ�������жϡ� // 的信息作类似判断。 311 if (!(dir = if
314
return dir;
-/* ��Ӧ��'/usr/'����� */ 342 if (!(base = if
lang=EN-US>
return base; // Ȼ���ڷ��صĶ���Ŀ¼��Ѱ��ָ���ļ���Ŀ¼���i�ڵ㡣ע�⣡��Ϊ������Ҳ��һ��Ŀ // 然后在返回的顶层目录中寻找指定文件名目录项的i节点。注意!因为如果最后也是一个目 // ¼���������û�м�'/'���᷵�ظ����Ŀ¼��i�ڵ㣡 ���磺/usr/src/linux����ֻ // 录名,但其后没有加'/',则不会返回该最后目录的i节点! 例如:/usr/src/linux,将只 // ���� src/Ŀ¼����i�ڵ㡣��Ϊ����dir_namei() ������'/'���������һ�����ֵ���һ�� // 返回 src/目录名的i节点。因为函数dir_namei() 将不以'/'结束的最后一个名字当作一个 // �ļ��������������������Ҫ�������������ʹ��Ѱ��Ŀ¼��i�ڵ㺯��find_entry()���� // 文件名来看待,因此这里需要单独对这种情况使用寻找目录项i节点函数find_entry()进行 // ��������ʱde�к���Ѱ�ҵ���Ŀ¼��ָ�룬��dir�ǰ�����Ŀ¼���Ŀ¼��i�ڵ�ָ�롣 // 处理。此时de中含有寻找到的目录项指针,而dir是包含该目录项的目录的i节点指针。 346 bh = NULL; 350 } // ����ȡ��Ŀ¼���i�ڵ�ţ����ͷŰ�����Ŀ¼��ĸ��ٻ���鲢�Ż�Ŀ¼i�ڵ㡣Ȼ��ȡ // 接着取该目录项的i节点号,并释放包含该目录项的高速缓冲块并放回目录i节点。然后取 // ��Ӧ�ڵ�ŵ�i�ڵ㣬���䱻����ʱ��Ϊ��ǰʱ�䣬�������ı�־����ظ�i�ڵ� // 对应节点号的i节点,修改其被访问时间为当前时间,并置已修改标志。最后返回该i节点 // ָ��inode�������ǰ������Ŀ¼����һ����������������ʹ��follow_link()�õ���ָ��� // 指针inode。如果当前处理的目录项是一个符号链接名,则使用follow_link()得到其指向的 // Ŀ¼������i�ڵ㡣 // 目录项名的i节点。 351 inr = de->inode; 365 //// ȡָ��·������i�ڵ㣬������������ӡ� //// 取指定路径名的i节点,不跟随符号链接。 // ������pathname
-- ·������ // 参数:pathname
+- 路径名。 // ���أ���Ӧ��i�ڵ㡣 // 返回:对应的i节点。 366 struct m_inode * */ * * �ú������������������ȡ��ָ��·�����Ƶ�i�ڵ㡣open��link����ʹ������ * 该函数被许多简单命令用于取得指定路径名称的i节点。open、link等则使用它们 * �Լ�����Ӧ����������������ģʽ'chmod'������������ú������㹻���ˡ� * 自己的相应函数。但对于象修改模式'chmod'等这样的命令,该函数已足够用了。 */ //// ȡָ��·������i�ڵ㣬����������ӡ� //// 取指定路径名的i节点,跟随符号链接。 // ������pathname
-- ·������ // 参数:pathname
+- 路径名。 // ���أ���Ӧ��i�ڵ㡣 // 返回:对应的i节点。 378 struct m_inode * */ * * open()����ʹ�õ�namei���� - ����ʵ�����������Ĵ��ļ����� * open()函数使用的namei函数 - 这其实几乎是完整的打开文件程序。 */ //// �ļ���namei������ //// 文件打开namei函数。 // ����filename���ļ�·������flag�Ǵ��ļ���־����ȡֵO_RDONLY��ֻ������ // 参数filename是文件路径名,flag是打开文件标志,可取值O_RDONLY(只读)、O_WRONLY // ��ֻд����O_RDWR����д�����Լ�O_CREAT����������O_EXCL���������ļ����벻���ڣ��� // (只写)或O_RDWR(读写),以及O_CREAT(创建)、O_EXCL(被创建文件必须不存在)、 // O_APPEND�����ļ�β�������ݣ�������һЩ��־����ϡ���������ô�����һ�����ļ����� // O_APPEND(在文件尾添加数据)等其他一些标志的组合。如果本调用创建了一个新文件,则 // mode������ָ���ļ����������ԡ���Щ������S_IRWXU���ļ��������ж���д��ִ��Ȩ�ޣ��� // mode就用于指定文件的许可属性。这些属性有S_IRWXU(文件宿主具有读、写和执行权限)、 // S_IRUSR���û����ж��ļ�Ȩ�ޣ���S_IRWXG�����Ա���ж���д��ִ��Ȩ�ޣ��ȵȡ������� // S_IRUSR(用户具有读文件权限)、S_IRWXG(组成员具有读、写和执行权限)等等。对于新 // �������ļ�����Щ����ֻӦ���ڽ������ļ��ķ��ʣ�������ֻ���ļ��Ĵ���Ҳ������һ // 创建的文件,这些属性只应用于将来对文件的访问,创建了只读文件的打开调用也将返回一 // ���ɶ�д���ļ�������μ������ļ�sys/stat.h��fcntl.h�� // 个可读写的文件句柄。参见包含文件sys/stat.h、fcntl.h。 // ���أ��ɹ�����0�����س����룻res_inode - ���ض�Ӧ�ļ�·������i�ڵ�ָ�롣 // 返回:成功返回0,否则返回出错码;res_inode - 返回对应文件路径名的i节点指针。 388 int open_namei(const char *
@@ -4118,19 +4118,19 @@ style='color:blue'>dir_entry * de; 396 // ���ȶԺ����������к����Ĵ���������ļ�����ģʽ��־��ֻ����0���������ļ������־ // 首先对函数参数进行合理的处理。如果文件访问模式标志是只读(0),但是文件截零标志 // O_TRUNCȴ��λ�ˣ������ļ���־������ֻд��־O_WRONLY����������ԭ�������ڽ��� // O_TRUNC却置位了,则在文件打开标志中添加只写标志O_WRONLY。这样做的原因是由于截零 // ��־O_TRUNC�������ļ���д����²���Ч��Ȼ��ʹ�õ�ǰ���̵��ļ��������������룬�� // 标志O_TRUNC必须在文件可写情况下才有效。然后使用当前进程的文件访问许可屏蔽码,屏 // �ε�����ģʽ�е���Ӧλ����������ͨ�ļ���־I_REGULAR���ñ�־�����ڴ��ļ����� // 蔽掉给定模式中的相应位,并添上普通文件标志I_REGULAR。该标志将用于打开的文件不存 // �ڶ���Ҫ�����ļ�ʱ����Ϊ���ļ���Ĭ�����ԡ��μ�����411���ϵ�ע�͡� // 在而需要创建文件时,作为新文件的默认属性。参见下面411行上的注释。 397 if ((flag & mode &= 0777
400 mode |= I_REGULAR;
-// �����ļ���־�����μ�include/const.h�ļ����� // Ȼ�����ָ����·����Ѱ�ҵ���Ӧ��i�ڵ㣬�Լ����Ŀ¼�����䳤�ȡ���ʱ������ // 然后根据指定的路径名寻找到对应的i节点,以及最顶端目录名及其长度。此时如果最顶端 // Ŀ¼������Ϊ0�� ����'/usr/' ����·���������������ô���������Ƕ�д���������ļ��� // 目录名长度为0( 例如'/usr/' 这种路径名的情况),那么若操作不是读写、创建和文件长 // �Ƚ�0�����ʾ���ڴ�һ��Ŀ¼���ļ�����������ֱ�ӷ��ظ�Ŀ¼��i�ڵ㲢����0�˳��� // 度截0,则表示是在打开一个目录名文件操作。于是直接返回该目录的i节点并返回0退出。 // ����˵�����̲����Ƿ������ǷŻظ�i�ڵ㣬���س����롣 // 否则说明进程操作非法,于是放回该i节点,返回出错码。 401 if (!(dir = EISDIR; 410 } // ���Ÿ�������õ������Ŀ¼����i�ڵ�dir�������в���ȡ��·�����ַ����������� // 接着根据上面得到的最顶层目录名的i节点dir,在其中查找取得路径名字符串中最后的文 // ������Ӧ��Ŀ¼��ṹde����ͬʱ�õ���Ŀ¼�����ڵĸ��ٻ�����ָ�롣 ����ø��ٻ��� // 件名对应的目录项结构de,并同时得到该目录项所在的高速缓冲区指针。 如果该高速缓冲 // ָ��ΪNULL�����ʾû���ҵ���Ӧ�ļ�����Ŀ¼����ֻ�����Ǵ����ļ�������
-��ʱ�� // 指针为NULL,则表示没有找到对应文件名的目录项,因此只可能是创建文件操作。
+此时如 // �����Ǵ����ļ�����Żظ�Ŀ¼��i�ڵ㣬���س������˳�������û��ڸ�Ŀ¼û��д��Ȩ // 果不是创建文件,则放回该目录的i节点,返回出错号退出。如果用户在该目录没有写的权 // ������Żظ�Ŀ¼��i�ڵ㣬���س������˳��� // 力,则放回该目录的i节点,返回出错号退出。 411 bh = EACCES; // ��������ȷ�����Ǵ�������������д�������ɡ� ������Ǿ���Ŀ¼i�ڵ��Ӧ�豸������ // 现在我们确定了是创建操作并且有写操作许可。 因此我们就在目录i节点对应设备上申请 // һ���µ�i�ڵ��·������ָ�����ļ�ʹ�á�
-��ʧ����Ż�Ŀ¼��i�ڵ㣬������û�п� // 一个新的i节点给路径名上指定的文件使用。
+若失败则放回目录的i节点,并返回没有空 // ������롣����ʹ�ø��� i�ڵ㣬������г�ʼ���ã��ýڵ���û�id����Ӧ�ڵ����ģ // 间出错码。否则使用该新 i节点,对其进行初始设置:置节点的用户id;对应节点访问模 // ʽ�������ı�־��Ȼ����ָ��Ŀ¼dir������һ����Ŀ¼� // 式;置已修改标志。然后并在指定目录dir中添加一个新目录项。 421
@@ -4308,21 +4308,21 @@ inode->i_dirt = 1; // ������ص�Ӧ�ú�����Ŀ¼��ĸ��ٻ�����ָ��ΪNULL�����ʾ����Ŀ¼�����ʧ�ܡ����� // 如果返回的应该含有新目录项的高速缓冲区指针为NULL,则表示添加目录项操作失败。于是 // ������i�ڵ���������Ӽ�����1���Żظ�i�ڵ���Ŀ¼��i�ڵ㲢���س������˳���
-���� // 将该新i节点的引用连接计数减1,放回该i节点与目录的i节点并返回出错码退出。
+否则 // ˵������Ŀ¼������ɹ��� �������������ø���Ŀ¼���һЩ��ʼֵ����i�ڵ��Ϊ������ // 说明添加目录项操作成功。 于是我们来设置该新目录项的一些初始值:置i节点号为新申请 // ����i�ڵ�ĺ��룻���ø��ٻ��������ı�־��
-Ȼ���ͷŸø��ٻ��������Ż�Ŀ¼��i�� // 到的i节点的号码;并置高速缓冲区已修改标志。
+然后释放该高速缓冲区,放回目录的i节 // �㡣������Ŀ¼���i�ڵ�ָ�룬���ɹ��˳��� // 点。返回新目录项的i节点指针,并成功退出。 430
@@ -4375,16 +4375,16 @@ return 0; 442 } // �����棨411�У���Ŀ¼��ȡ�ļ�����ӦĿ¼��ṹ�IJ����ɹ�����bh��ΪNULL������˵ // 若上面(411行)在目录中取文件名对应目录项结构的操作成功(即bh不为NULL),则说 // ��ָ�����ļ��Ѿ����ڡ�����ȡ����Ŀ¼���i�ڵ�ź��������豸�ţ����ͷŸø��� // 明指定打开的文件已经存在。于是取出该目录项的i节点号和其所在设备号,并释放该高速 // �������Լ��Ż�Ŀ¼��i�ڵ㡣�����ʱ��ռ������־O_EXCL��λ���������ļ��Ѿ����ڣ� // 缓冲区以及放回目录的i节点。如果此时独占操作标志O_EXCL置位,但现在文件已经存在, // ���ļ��Ѵ��ڳ������˳��� // 则返回文件已存在出错码退出。 443 inr = de->inode; 449 } // Ȼ�����Ƕ�ȡ��Ŀ¼���i�ڵ����ݡ�����i�ڵ���һ��Ŀ¼��i�ڵ㲢�ҷ���ģʽ��ֻ // 然后我们读取该目录项的i节点内容。若该i节点是一个目录的i节点并且访问模式是只 // д���д������û�з��ʵ�����Ȩ�ޣ���Żظ�i�ڵ㣬���ط���Ȩ�������˳��� // 写或读写,或者没有访问的许可权限,则放回该i节点,返回访问权限出错码退出。 450 if (!(inode = EPERM; 456 } // �������Ǹ��¸�i�ڵ�ķ���ʱ���ֶ�ֵΪ��ǰʱ�䡣��������˽�0��־����i�� // 接着我们更新该i节点的访问时间字段值为当前时间。如果设立了截0标志,则将该i节 // ����ļ����Ƚ�Ϊ0����ظ�Ŀ¼��i�ڵ��ָ�룬������0���ɹ����� // 点的文件长度截为0。最后返回该目录项i节点的指针,并返回0(成功)。 457 inode->i_atime =
@@ -4478,20 +4478,20 @@ lang=EN-US> } 463 //// ����һ���豸�����ļ�����ͨ�ļ��ڵ㣨node���� //// 创建一个设备特殊文件或普通文件节点(node)。 // �ú�����������Ϊfilename����mode��devָ�����ļ�ϵͳ�ڵ㣨��ͨ�ļ����豸������ // 该函数创建名称为filename,由mode和dev指定的文件系统节点(普通文件、设备特殊文 // ���������ܵ����� // 件或命名管道)。 // ������filename
-- ·������mode - ָ��ʹ�������Լ��������ڵ�����ͣ�dev
-- �豸�š� // 参数:filename
+- 路径名;mode - 指定使用许可以及所创建节点的类型;dev
+- 设备号。 // ���أ��ɹ���0�����س����롣 // 返回:成功则返回0,否则返回出错码。 464 int sys_mknod(const char *
@@ -4522,19 +4522,19 @@ style='color:blue'>dir_entry * de; 471 // ���ȼ��������ɺͲ�������Ч�Բ�ȡ·�����ж���Ŀ¼��i�ڵ㡣������dz����û����� // 首先检查操作许可和参数的有效性并取路径名中顶层目录的i节点。如果不是超级用户,则 // ���ط������ɳ����롣����Ҳ�����Ӧ·�����ж���Ŀ¼��i�ڵ㣬�س����롣����� // 返回访问许可出错码。如果找不到对应路径名中顶层目录的i节点,则返回出错码。如果最 // ���˵��ļ�������Ϊ0����˵��������·�������û��ָ���ļ������Żظ�Ŀ¼i�ڵ㣬�� // 顶端的文件名长度为0,则说明给出的路径名最后没有指定文件名,放回该目录i节点,返 // �س������˳�������ڸ�Ŀ¼��û��д��Ȩ�ޣ���Żظ�Ŀ¼��i�ڵ㣬���ط������ɳ��� // 回出错码退出。如果在该目录中没有写的权限,则放回该目录的i节点,返回访问许可出错 // ���˳���������dz����û����ط������ɳ����롣 // 码退出。如果不是超级用户,则返回访问许可出错码。 472 if (!EPERM; 483 } // Ȼ����������һ��·����ָ�����ļ��Ƿ��Ѿ����ڡ����Ѿ��������ܴ���ͬ���ļ��ڵ㡣 // 然后我们搜索一下路径名指定的文件是否已经存在。若已经存在则不能创建同名文件节点。 // �����Ӧ·�����������ļ�����Ŀ¼���Ѿ����ڣ����ͷŰ�����Ŀ¼��Ļ������鲢�Ż� // 如果对应路径名上最后的文件名的目录项已经存在,则释放包含该目录项的缓冲区块并放回 // Ŀ¼��i�ڵ㣬�����ļ��Ѿ����ڵij������˳��� // 目录的i节点,返回文件已经存在的出错码退出。 484 bh = EEXIST; 489 } // �������Ǿ�����һ���µ�i�ڵ㣬�����ø�i�ڵ������ģʽ�����Ҫ�������ǿ��豸�ļ� // 否则我们就申请一个新的i节点,并设置该i节点的属性模式。如果要创建的是块设备文件 // �������ַ��豸�ļ�������i�ڵ��ֱ������ָ��0�����豸�š��������豸�ļ���˵�� // 或者是字符设备文件,则令i节点的直接逻辑块指针0等于设备号。即对于设备文件来说, // ��i�ڵ��i_zone[0]�д�ŵ��Ǹ��豸�ļ��������豸���豸�š�Ȼ�����ø�i�ڵ���� // 其i节点的i_zone[0]中存放的是该设备文件所定义设备的设备号。然后设置该i节点的修 // ��ʱ�䡢����ʱ��Ϊ��ǰʱ�䣬������i�ڵ����ı�־�� // 改时间、访问时间为当前时间,并设置i节点已修改标志。 490 inode = new_inode(dir->i_dev); 491 if (!inode) {
-// �����ɹ���Ż�Ŀ¼i�ڵ㣬�����ռ�������˳��� 492
@@ -4662,13 +4662,13 @@ inode->i_atime = CURRENT_TIME;<
lang=EN-US> inode->i_dirt =
1; // ����Ϊ����µ�i�ڵ���Ŀ¼��������һ��Ŀ¼����ʧ�ܣ�������Ŀ¼��ĸ��ٻ��� // 接着为这个新的i节点在目录中新添加一个目录项。如果失败(包含该目录项的高速缓冲 // ��ָ��ΪNULL������Ż�Ŀ¼��i�ڵ㣻���������i�ڵ��������Ӽ�����λ�����Żظ� // 块指针为NULL),则放回目录的i节点;把所申请的i节点引用连接计数复位,并放回该 // i�ڵ㣬���س������˳��� // i节点,返回出错码退出。 500 bh = ENOSPC; 506 } // ��������Ŀ¼�����Ҳ�ɹ��ˣ������������������Ŀ¼�����ݡ����Ŀ¼���i�ڵ��� // 现在添加目录项操作也成功了,于是我们来设置这个目录项内容。令该目录项的i节点字 // �ε�����i�ڵ�ţ����ø��ٻ��������ı�־���Ż�Ŀ¼���µ�i�ڵ㣬�ͷŸ��ٻ��� // 段等于新i节点号,并置高速缓冲区已修改标志,放回目录和新的i节点,释放高速缓冲 // �������0(�ɹ�)�� // 区,最后返回0(成功)。 507 de->inode =
@@ -4733,13 +4733,13 @@ lang=EN-US> } 514 //// ����һ��Ŀ¼�� //// 创建一个目录。 // ������pathname
-- ·������mode - Ŀ¼ʹ�õ�Ȩ�����ԡ� // 参数:pathname
+- 路径名;mode - 目录使用的权限属性。 // ���أ��ɹ���0�����س����롣 // 返回:成功则返回0,否则返回出错码。 515 int sys_mkdir(const char *
@@ -4770,16 +4770,16 @@ style='color:blue'>dir_entry * de; 522 // ���ȼ���������Ч�Բ�ȡ·�����ж���Ŀ¼��i�ڵ㡣����Ҳ�����Ӧ·�����ж���Ŀ¼ // 首先检查参数的有效性并取路径名中顶层目录的i节点。如果找不到对应路径名中顶层目录 // ��i�ڵ㣬�س����롣�����˵��ļ�������Ϊ0����˵��������·�������û��ָ // 的i节点,则返回出错码。如果最顶端的文件名长度为0,则说明给出的路径名最后没有指 // ���ļ������Żظ�Ŀ¼i�ڵ㣬���س������˳�������ڸ�Ŀ¼��û��д��Ȩ�ޣ���Żظ� // 定文件名,放回该目录i节点,返回出错码退出。如果在该目录中没有写的权限,则放回该 // Ŀ¼��i�ڵ㣬���ط������ɳ������˳���������dz����û����ط������ɳ����롣 // 目录的i节点,返回访问许可出错码退出。如果不是超级用户,则返回访问许可出错码。 523 if (!(dir = EPERM; 532 } // Ȼ����������һ��·����ָ����Ŀ¼���Ƿ��Ѿ����ڡ����Ѿ��������ܴ���ͬ��Ŀ¼�ڵ㡣 // 然后我们搜索一下路径名指定的目录名是否已经存在。若已经存在则不能创建同名目录节点。 // �����Ӧ·����������Ŀ¼����Ŀ¼���Ѿ����ڣ����ͷŰ�����Ŀ¼��Ļ������鲢�Ż� // 如果对应路径名上最后的目录名的目录项已经存在,则释放包含该目录项的缓冲区块并放回 // Ŀ¼��i�ڵ㣬�����ļ��Ѿ����ڵij������˳����������Ǿ�����һ���µ�i�ڵ㣬������ // 目录的i节点,返回文件已经存在的出错码退出。否则我们就申请一个新的i节点,并设置 // ��i�ڵ������ģʽ���ø���i�ڵ��Ӧ���ļ�����Ϊ32�ֽ� ��2��Ŀ¼��Ĵ�С������ // 该i节点的属性模式:置该新i节点对应的文件长度为32字节 (2个目录项的大小)、置 // �ڵ����ı�־���Լ��ڵ����ʱ��ͷ���ʱ�䡣2��Ŀ¼��ֱ�����'.'��'..'Ŀ¼�� // 节点已修改标志,以及节点的修改时间和访问时间。2个目录项分别用于'.'和'..'目录。 533 bh = new_inode(dir->i_dev); 540 if (!inode) {
-// �����ɹ���Ż�Ŀ¼��i�ڵ㣬�����ռ�����롣 541
@@ -4886,14 +4886,14 @@ lang=EN-US> inode->i_dirt =
lang=EN-US> inode->i_mtime =
inode->i_atime = CURRENT_TIME; // ����Ϊ����i�ڵ�����һ���ڱ���Ŀ¼�����ݵĴ��̿飬����i�ڵ�ĵ�һ��ֱ�ӿ�ָ��� // 接着为该新i节点申请一用于保存目录项数据的磁盘块,并令i节点的第一个直接块指针等 // �ڸÿ�š��������ʧ����Żض�ӦĿ¼��i�ڵ㣻��λ�������i�ڵ����Ӽ������Żظ� // 于该块号。如果申请失败则放回对应目录的i节点;复位新申请的i节点连接计数;放回该 // �µ�i�ڵ㣬����û�пռ�������˳��������ø��µ�i�ڵ����ı�־�� // 新的i节点,返回没有空间出错码退出。否则置该新的i节点已修改标志。 547 if
@@ -4923,12 +4923,12 @@ lang=EN-US> } // ���豸�϶�ȡ������Ĵ��̿飨Ŀ���ǰѶ�Ӧ��ŵ����ٻ������У�������������Żض�Ӧ // 从设备上读取新申请的磁盘块(目的是把对应块放到高速缓冲区中)。若出错,则放回对应 // Ŀ¼��i�ڵ㣻�ͷ�����Ĵ��̿飻��λ�������i�ڵ����Ӽ������Żظ��µ�i�ڵ㣬�� // 目录的i节点;释放申请的磁盘块;复位新申请的i节点连接计数;放回该新的i节点,返 // ��û�пռ�������˳��� // 回没有空间出错码退出。 554 if (!(dir_block=ERROR; 559 } // Ȼ�������ڻ�����н�����������Ŀ¼�ļ��е�2��Ĭ�ϵ���Ŀ¼�'.'��'..'���ṹ�� // 然后我们在缓冲块中建立起所创建目录文件中的2个默认的新目录项('.'和'..')结构数 // �ݡ�������deָ����Ŀ¼������ݿ飬Ȼ���ø�Ŀ¼���i�ڵ���ֶε����������i // 据。首先令de指向存放目录项的数据块,然后置该目录项的i节点号字段等于新申请的i // �ڵ�ţ������ֶε���"."�� Ȼ��deָ����һ��Ŀ¼��ṹ�����ڸýṹ�д���ϼ�Ŀ¼ // 节点号,名字字段等于"."。 然后de指向下一个目录项结构,并在该结构中存放上级目录 // �� i�ڵ�ź�����".."��Ȼ�����øø��ٻ�������ı�־�����ͷŸû���顣�ٳ�ʼ�� // 的 i节点号和名字".."。然后设置该高速缓冲块已修改标志,并释放该缓冲块。再初始化 // ������i�ڵ��ģʽ�ֶΣ����ø�i�ڵ����ı�־�� // 设置新i节点的模式字段,并置该i节点已修改标志。 560 de = (struct dir_entry *) dir_block->b_data; 561
de->inode=inode->i_num; //
-����'.'Ŀ¼� 562 de++; 564 de->inode =
dir->i_num;
- // ����'..'Ŀ¼� 565 I_DIRECTORY | (mode & 0777 &
lang=EN-US> inode->i_dirt =
1; // ����������ָ��Ŀ¼��������һ��Ŀ¼����ڴ���½�Ŀ¼��i�ڵ��Ŀ¼�������ʧ // 现在我们在指定目录中新添加一个目录项,用于存放新建目录的i节点和目录名。如果失 // �ܣ�������Ŀ¼��ĸ��ٻ�����ָ��ΪNULL������Ż�Ŀ¼��i�ڵ㣻�������i�ڵ��� // 败(包含该目录项的高速缓冲区指针为NULL),则放回目录的i节点;所申请的i节点引 // �����Ӽ�����λ�����Żظ�i�ڵ㡣���س������˳��� // 用连接计数复位,并放回该i节点。返回出错码退出。 571 bh = ENOSPC; 577 } // ��������Ŀ¼���i�ڵ��ֶε�����i�ڵ�ţ����ø��ٻ�������ı�־���Ż�Ŀ¼ // 最后令该新目录项的i节点字段等于新i节点号,并置高速缓冲块已修改标志,放回目录 // ���µ�i�ڵ㣬�ͷŸ��ٻ����������0���ɹ����� // 和新的i节点,释放高速缓冲区,最后返回0(成功)。 578 de->inode =
@@ -5101,18 +5101,18 @@ lang=EN-US> */ /* * ���ڼ��ָ����Ŀ¼�Ƿ�Ϊ�յ��ӳ�������rmdirϵͳ���ã��� * 用于检查指定的目录是否为空的子程序(用于rmdir系统调用)。 */ //// ���ָ��Ŀ¼�Ƿ�ա� //// 检查指定目录是否空。 // ������inode
-- ָ��Ŀ¼��i�ڵ�ָ�롣 // 参数:inode
+- 指定目录的i节点指针。 // ���أ�1 �C
-Ŀ¼���ǿյģ�0 - ���ա� // 返回:1 –
+目录中是空的;0 - 不空。 591 static int empty_dir(struct dir_entry * de; 597 // ���ȼ���ָ��Ŀ¼������Ŀ¼���������鿪ʼ�����ض�Ŀ¼������Ϣ�Ƿ���ȷ��һ��Ŀ¼ // 首先计算指定目录中现有目录项个数并检查开始两个特定目录项中信息是否正确。一个目录 // ��Ӧ��������2��Ŀ¼���"."��".."�� ���Ŀ¼���������2�����߸�Ŀ¼i�ڵ�ĵ� // 中应该起码有2个目录项:即"."和".."。 如果目录项个数少于2个或者该目录i节点的第 // 1��ֱ�ӿ�û��ָ���κδ��̿�ţ����߸�ֱ�ӿ������������ʾ������Ϣ���豸dev ��Ŀ // 1个直接块没有指向任何磁盘块号,或者该直接块读不出,则显示警告信息“设备dev 上目 // ¼����������0(ʧ��)�� // 录错”,返回0(失败)。 598 len =
inode->i_size / sizeof (struct dir_entry);
-// Ŀ¼��Ŀ¼������� 599 if (len<2 ||
@@ -5177,26 +5177,26 @@ return 0; 603 } // ��ʱbh��ָ������к���Ŀ¼�����ݡ�������Ŀ¼��ָ��deָ����е�1��Ŀ¼� // 此时bh所指缓冲块中含有目录项数据。我们让目录项指针de指向缓冲块中第1个目录项。 // ���ڵ�1��Ŀ¼�"."��������i�ڵ���ֶ�inodeӦ�õ��ڵ�ǰĿ¼��i�ڵ�š����� // 对于第1个目录项("."),它的i节点号字段inode应该等于当前目录的i节点号。对于 // ��2��Ŀ¼�".."��������i�ڵ���ֶ� inode Ӧ�õ�����һ��Ŀ¼��i�ڵ�ţ����� // 第2个目录项(".."),它的i节点号字段 inode 应该等于上一层目录的i节点号,不会 // Ϊ0����������1��Ŀ¼���i�ڵ���ֶ�ֵ�����ڸ�Ŀ¼��i�ڵ�ţ����ߵ�2��Ŀ¼ // 为0。因此如果第1个目录项的i节点号字段值不等于该目录的i节点号,或者第2个目录 // ���i�ڵ���ֶ�Ϊ�㣬��������Ŀ¼��������ֶβ��ֱ����"."��".."������ʾ������ // 项的i节点号字段为零,或者两个目录项的名字字段不分别等于"."和"..",则显示出错警 // ����Ϣ���豸dev��Ŀ¼������������0�� // 告信息“设备dev上目录错”,并返回0。 604 de = (struct 609 } // Ȼ��������nr����Ŀ¼����ţ���0��ʼ�ƣ���deָ�������Ŀ¼���ѭ������Ŀ¼ // 然后我们令nr等于目录项序号(从0开始计);de指向第三个目录项。并循环检测该目录 // ���������еģ�len - 2����Ŀ¼�����û��Ŀ¼���i�ڵ���ֶβ�Ϊ0����ʹ�ã��� // 中其余所有的(len - 2)个目录项,看有没有目录项的i节点号字段不为0(被使用)。 610 nr = 2; 612 while (nr<len) { // ����ÿ���̿��е�Ŀ¼���Ѿ�ȫ�������ϣ����ͷŸô��̿�Ļ���飬����ȡĿ¼���� // 如果该块磁盘块中的目录项已经全部检测完毕,则释放该磁盘块的缓冲块,并读取目录数据 // �ļ�����һ�麬��Ŀ¼��Ĵ��̿顣��ȡ�ķ����Ǹ��ݵ�ǰ����Ŀ¼����� nr ������� // 文件中下一块含有目录项的磁盘块。读取的方法是根据当前检测的目录项序号 nr 计算出对 // ӦĿ¼����Ŀ¼�����ļ��е����ݿ�ţ�nr/DIR_ENTRIES_PER_BLOCK����Ȼ��ʹ�� bmap() // 应目录项在目录数据文件中的数据块号(nr/DIR_ENTRIES_PER_BLOCK),然后使用 bmap() // ����ȡ�ö�Ӧ���̿�� block����ʹ�ö��豸�̿麯��bread() ����Ӧ�̿���뻺����У� // 函数取得对应的盘块号 block,再使用读设备盘块函数bread() 把相应盘块读入缓冲块中, // �����ظû�����ָ�롣������ȡ����Ӧ�̿�û��ʹ�ã����Ѿ����ã����ļ��Ѿ�ɾ���ȣ��� // 并返回该缓冲块的指针。若所读取的相应盘块没有使用(或已经不用,如文件已经删除等), // ���������һ�飬�������������������0��������deָ����������Ŀ¼� // 则继续读下一块,若读不出,则出错返回0。否则让de指向读出块的首个目录项。 613
@@ -5301,14 +5301,14 @@ de = (struct dir_entry *) bh->b_data;<
lang=EN-US>
} // ����deָ��ĵ�ǰĿ¼������Ŀ¼���i�ڵ���ֶβ�����0�����ʾ��Ŀ¼��Ŀǰ�� // 对于de指向的当前目录项,如果该目录项的i节点号字段不等于0,则表示该目录项目前正 // ��ʹ�ã����ͷŸø��ٻ�����������0�˳�����������û�в�ѯ���Ŀ¼�е�����Ŀ¼� // 被使用,则释放该高速缓冲区,返回0退出。否则,若还没有查询完该目录中的所有目录项, // ���Ŀ¼�����nr��1��deָ����һ��Ŀ¼�������⡣ // 则把目录项序号nr增1、de指向下一个目录项,继续检测。 624
@@ -5337,8 +5337,8 @@ lang=EN-US> &nb
630 } // ִ�е�����˵����Ŀ¼��û���ҵ����õ�Ŀ¼��(��Ȼ����ͷ��������)�����ͷŻ���鷵��1�� // 执行到这里说明该目录中没有找到已用的目录项(当然除了头两个以外),则释放缓冲块返回1。 631 } //// ɾ��Ŀ¼�� //// 删除目录。 // ������ name
-- Ŀ¼����·�������� // 参数: name
+- 目录名(路径名)。 // ���أ�����0��ʾ�ɹ������س����š� // 返回:返回0表示成功,否则返回出错号。 635 int sys_rmdir(const char *
@@ -5389,16 +5389,16 @@ style='color:blue'>dir_entry * de; // ���ȼ���������Ч�Բ�ȡ·�����ж���Ŀ¼��i�ڵ㡣����Ҳ�����Ӧ·�����ж���Ŀ¼ // 首先检查参数的有效性并取路径名中顶层目录的i节点。如果找不到对应路径名中顶层目录 // ��i�ڵ㣬�س����롣�����˵��ļ�������Ϊ0����˵��������·�������û��ָ // 的i节点,则返回出错码。如果最顶端的文件名长度为0,则说明给出的路径名最后没有指 // ���ļ������Żظ�Ŀ¼i�ڵ㣬���س������˳�������ڸ�Ŀ¼��û��д��Ȩ�ޣ���Żظ� // 定文件名,放回该目录i节点,返回出错码退出。如果在该目录中没有写的权限,则放回该 // Ŀ¼��i�ڵ㣬���ط������ɳ������˳���������dz����û����ط������ɳ����롣 // 目录的i节点,返回访问许可出错码退出。如果不是超级用户,则返回访问许可出错码。 643 if (!(dir = EPERM; 652 } // Ȼ�����ָ��Ŀ¼��i�ڵ��Ŀ¼�����ú���find_entry()Ѱ�Ҷ�ӦĿ¼������ذ����� // 然后根据指定目录的i节点和目录名利用函数find_entry()寻找对应目录项,并返回包含该 // Ŀ¼��Ļ����ָ��bh��������Ŀ¼���Ŀ¼��i�ڵ�ָ��dir��Ŀ¼��ָ��de���ٸ��� // 目录项的缓冲块指针bh、包含该目录项的目录的i节点指针dir和该目录项指针de。再根据 // ��Ŀ¼��de
-�е�i�ڵ������ iget()�����õ���Ӧ��i�ڵ� inode�������Ӧ·�������� // 该目录项de
+中的i节点号利用 iget()函数得到对应的i节点 inode。如果对应路径名上最 // ��Ŀ¼����Ŀ¼����ڣ����ͷŰ�����Ŀ¼��ĸ��ٻ��������Ż�Ŀ¼��
-i�ڵ㣬������ // 后目录名的目录项不存在,则释放包含该目录项的高速缓冲区,放回目录的
+i节点,返回文 // ���Ѿ����ڳ����룬���˳������ȡĿ¼���i�ڵ��������Ż�Ŀ¼�� i�ڵ㣬���ͷź� // 件已经存在出错码,并退出。如果取目录项的i节点出错,则放回目录的 i节点,并释放含 // ��Ŀ¼��ĸ��ٻ����������س����š� // 有目录项的高速缓冲区,返回出错号。 653 bh = EPERM; 662 } // ��ʱ�������а���Ҫ��ɾ��Ŀ¼���Ŀ¼i�ڵ�dir��Ҫ��ɾ��Ŀ¼���i�ڵ�inode��Ҫ // 此时我们已有包含要被删除目录项的目录i节点dir、要被删除目录项的i节点inode和要 // ��ɾ��Ŀ¼��ָ��de����������ͨ������3����������Ϣ�ļ������֤ɾ�������Ŀ����ԡ� // 被删除目录项指针de。下面我们通过对这3个对象中信息的检查来验证删除操作的可行性。 // ����Ŀ¼����������ɾ����־���ҽ��̵���Ч�û�id��euid������root�����ҽ��̵���Ч // 若该目录设置了受限删除标志并且进程的有效用户id(euid)不是root,并且进程的有效 // �û�id��euid�������ڸ�i�ڵ���û�id�����ʾ��ǰ����û��Ȩ��ɾ����Ŀ¼�����Ƿ� // 用户id(euid)不等于该i节点的用户id,则表示当前进程没有权限删除该目录,于是放 // �ذ���Ҫɾ��Ŀ¼����Ŀ¼ i�ڵ��Ҫɾ��Ŀ¼�� i�ڵ㣬Ȼ���ͷŸ��ٻ����������� // 回包含要删除目录名的目录 i节点和该要删除目录的 i节点,然后释放高速缓冲区,返回 // �����롣 // 出错码。 663 if ((dir->i_mode
@@ -5543,14 +5543,14 @@ return -EPERM; 669 } // ���Ҫ��ɾ����Ŀ¼��i�ڵ���豸�Ų����ڰ�����Ŀ¼���Ŀ¼���豸�ţ����߸ñ�ɾ�� // 如果要被删除的目录项i节点的设备号不等于包含该目录项的目录的设备号,或者该被删除 // Ŀ¼���������Ӽ������� 1����ʾ�з������ӵȣ�������ɾ����Ŀ¼�������ͷŰ���Ҫɾ // 目录的引用连接计数大于 1(表示有符号连接等),则不能删除该目录。于是释放包含要删 // ��Ŀ¼����Ŀ¼i�ڵ��Ҫɾ��Ŀ¼��i�ڵ㣬�ͷŸ��ٻ���飬���س����롣 // 除目录名的目录i节点和该要删除目录的i节点,释放高速缓冲块,返回出错码。 670 if (inode->i_dev
@@ -5575,13 +5575,13 @@ return -EPERM; 675 } // ���Ҫ��ɾ��Ŀ¼��Ŀ¼��i�ڵ�͵��ڰ�������ɾ��Ŀ¼��Ŀ¼i�ڵ㣬���ʾ��ͼɾ�� // 如果要被删除目录的目录项i节点就等于包含该需删除目录的目录i节点,则表示试图删除 // "."Ŀ¼�����Dz������ġ����ǷŻذ���Ҫɾ��Ŀ¼����Ŀ¼i�ڵ��Ҫɾ��Ŀ¼��i�ڵ㣬 // "."目录,这是不允许的。于是放回包含要删除目录名的目录i节点和要删除目录的i节点, // �ͷŸ��ٻ���飬���س����롣 // 释放高速缓冲块,返回出错码。 676 if (inode == dir)
@@ -5607,11 +5607,11 @@ return -EPERM; 681 } // ��Ҫ��ɾ��Ŀ¼i�ڵ�����Ա����ⲻ��һ��Ŀ¼����ɾ��������ǰ����ȫ�����ڡ����� // 若要被删除目录i节点的属性表明这不是一个目录,则本删除操作的前提完全不存在。于是 // �Żذ���ɾ��Ŀ¼����Ŀ¼i�ڵ��Ҫɾ��Ŀ¼��i�ڵ㣬�ͷŸ��ٻ���飬���س����롣 // 放回包含删除目录名的目录i节点和该要删除目录的i节点,释放高速缓冲块,返回出错码。 682 if (!ENOTDIR; 687 } // �����豻ɾ����Ŀ¼���գ���Ҳ����ɾ�������ǷŻذ���Ҫɾ��Ŀ¼����Ŀ¼i�ڵ��Ҫ // 若该需被删除的目录不空,则也不能删除。于是放回包含要删除目录名的目录i节点和该要 // ɾ��Ŀ¼��i�ڵ㣬�ͷŸ��ٻ���飬���س����롣 // 删除目录的i节点,释放高速缓冲块,返回出错码。 688 if (!ENOTEMPTY; 693 } // ����һ����Ŀ¼����Ŀ¼��������Ӧ��Ϊ2�����ӵ��ϲ�Ŀ¼�ͱ�Ŀ¼���������豻ɾ��Ŀ // 对于一个空目录,其目录项链接数应该为2(链接到上层目录和本目录)。若该需被删除目 // ¼��i�ڵ��������������2������ʾ������Ϣ����ɾ��������Ȼ����ִ�С������ø��豻 // 录的i节点的连接数不等于2,则显示警告信息。但删除操作仍然继续执行。于是置该需被 // ɾ��Ŀ¼��Ŀ¼���i�ڵ���ֶ�Ϊ0����ʾ��Ŀ¼���ʹ�ã����ú��и�Ŀ¼��ĸ��� // 删除目录的目录项的i节点号字段为0,表示该目录项不再使用,并置含有该目录项的高速 // ��������ı�־�����ͷŸû���顣Ȼ�����ñ�ɾ��Ŀ¼i�ڵ��������Ϊ0����ʾ���У��� // 缓冲块已修改标志,并释放该缓冲块。然后再置被删除目录i节点的链接数为0(表示空闲), // ����i�ڵ����ı�־�� // 并置i节点已修改标志。 694 if
@@ -5704,13 +5704,13 @@ inode->i_nlinks=0; 700 inode->i_dirt=1; // �ٽ�������ɾ��Ŀ¼����Ŀ¼��i�ڵ����Ӽ�����1������ı�ʱ�����ʱ��Ϊ��ǰʱ // 再将包含被删除目录名的目录的i节点链接计数减1,修改其改变时间和修改时间为当前时 // �䣬���øýڵ����ı�־�����Żذ���Ҫɾ��Ŀ¼����Ŀ¼i�ڵ��Ҫɾ��Ŀ¼��i // 间,并置该节点已修改标志。最后放回包含要删除目录名的目录i节点和该要删除目录的i // �ڵ㣬����0��ɾ�������ɹ����� // 节点,返回0(删除操作成功)。 701 dir->i_nlinks--; //// ɾ�����ͷţ��ļ�����Ӧ��Ŀ¼� //// 删除(释放)文件名对应的目录项。 // ���ļ�ϵͳɾ��һ�����֡�������ļ������һ�����ӣ�����û�н��������ļ������ // 从文件系统删除一个名字。如果是文件的最后一个链接,并且没有进程正打开该文件,则该 // �ļ�Ҳ����ɾ�������ͷ���ռ�õ��豸�ռ䡣 // 文件也将被删除,并释放所占用的设备空间。 // ������name
-- �ļ�����·�������� // 参数:name
+- 文件名(路径名)。 // ���أ��ɹ���0�����س����š� // 返回:成功则返回0,否则返回出错号。 709 int sys_unlink(const char *
@@ -5780,19 +5780,19 @@ style='color:blue'>dir_entry * de; 716 // ���ȼ���������Ч�Բ�ȡ·�����ж���Ŀ¼��i�ڵ㡣����Ҳ�����Ӧ·�����ж���Ŀ¼ // 首先检查参数的有效性并取路径名中顶层目录的i节点。如果找不到对应路径名中顶层目录 // �� i�ڵ㣬�س����롣�����˵��ļ�������Ϊ0����˵��������·�������û��ָ // 的 i节点,则返回出错码。如果最顶端的文件名长度为0,则说明给出的路径名最后没有指 // ���ļ������Żظ�Ŀ¼i�ڵ㣬���س������˳�������ڸ�Ŀ¼��û��д��Ȩ�ޣ���Żظ� // 定文件名,放回该目录i节点,返回出错码退出。如果在该目录中没有写的权限,则放回该 // Ŀ¼��i�ڵ㣬���ط������ɳ������˳�������Ҳ�����Ӧ·��������Ŀ¼��i�ڵ㣬�� // 目录的i节点,返回访问许可出错码退出。如果找不到对应路径名顶层目录的i节点,则返 // �س����롣 // 回出错码。 717 if (!(dir = EPERM; 726 } // Ȼ�����ָ��Ŀ¼��i�ڵ��Ŀ¼�����ú���find_entry()Ѱ�Ҷ�ӦĿ¼������ذ����� // 然后根据指定目录的i节点和目录名利用函数find_entry()寻找对应目录项,并返回包含该 // Ŀ¼��Ļ����ָ��bh��������Ŀ¼���Ŀ¼��i�ڵ�ָ��dir��Ŀ¼��ָ��de���ٸ��� // 目录项的缓冲块指针bh、包含该目录项的目录的i节点指针dir和该目录项指针de。再根据 // ��Ŀ¼��de
-�е�i�ڵ������ iget()�����õ���Ӧ��i�ڵ� inode�������Ӧ·�������� // 该目录项de
+中的i节点号利用 iget()函数得到对应的i节点 inode。如果对应路径名上最 // ��Ŀ¼����Ŀ¼����ڣ����ͷŰ�����Ŀ¼��ĸ��ٻ��������Ż�Ŀ¼��
-i�ڵ㣬������ // 后目录名的目录项不存在,则释放包含该目录项的高速缓冲区,放回目录的
+i节点,返回文 // ���Ѿ����ڳ����룬���˳������ȡĿ¼���i�ڵ��������Ż�Ŀ¼�� i�ڵ㣬���ͷź� // 件已经存在出错码,并退出。如果取目录项的i节点出错,则放回目录的 i节点,并释放含 // ��Ŀ¼��ĸ��ٻ����������س����š� // 有目录项的高速缓冲区,返回出错号。 727 bh = ENOENT; 736 } // ��ʱ�������а���Ҫ��ɾ��Ŀ¼���Ŀ¼i�ڵ�dir��Ҫ��ɾ��Ŀ¼���i�ڵ�inode��Ҫ // 此时我们已有包含要被删除目录项的目录i节点dir、要被删除目录项的i节点inode和要 // ��ɾ��Ŀ¼��ָ��de����������ͨ������3����������Ϣ�ļ������֤ɾ�������Ŀ����ԡ� // 被删除目录项指针de。下面我们通过对这3个对象中信息的检查来验证删除操作的可行性。 // ����Ŀ¼����������ɾ����־���ҽ��̵���Ч�û�id��euid������root�����ҽ��̵� // 若该目录设置了受限删除标志并且进程的有效用户id(euid)不是root,并且进程的euid // �����ڸ�i�ڵ���û�id�����ҽ��̵�euidҲ������Ŀ¼i�ڵ���û�id�����ʾ��ǰ�� // 不等于该i节点的用户id,并且进程的euid也不等于目录i节点的用户id,则表示当前进 // ��û��Ȩ��ɾ����Ŀ¼�����ǷŻذ���Ҫɾ��Ŀ¼����Ŀ¼i�ڵ��Ҫɾ��Ŀ¼��i�ڵ㣬 // 程没有权限删除该目录,于是放回包含要删除目录名的目录i节点和该要删除目录的i节点, // Ȼ���ͷŸ��ٻ���飬���س����롣 // 然后释放高速缓冲块,返回出错码。 737 if ((dir->i_mode
@@ -5944,10 +5944,10 @@ return -EPERM; 744 } // �����ָ���ļ�����һ��Ŀ¼����Ҳ����ɾ�����Żظ�Ŀ¼i�ڵ���ļ���Ŀ¼���i�� // 如果该指定文件名是一个目录,则也不能删除。放回该目录i节点和该文件名目录项的i节 // �㣬�ͷŰ�����Ŀ¼��Ļ���飬���س����š� // 点,释放包含该目录项的缓冲块,返回出错号。 745 if (EPERM; 750 } // �����i�ڵ�����Ӽ���ֵ�Ѿ�Ϊ0������ʾ������Ϣ����������Ϊ1�� // 如果该i节点的链接计数值已经为0,则显示警告信息,并修正其为1。 751 if
@@ -5995,10 +5995,10 @@ inode->i_nlinks=1; 755 } // �������ǿ���ɾ���ļ�����Ӧ��Ŀ¼���ˡ����ǽ����ļ���Ŀ¼���е�i�ڵ���ֶ���Ϊ0�� // 现在我们可以删除文件名对应的目录项了。于是将该文件名目录项中的i节点号字段置为0, // ��ʾ�ͷŸ�Ŀ¼������ð�����Ŀ¼��Ļ�������ı�־���ͷŸø��ٻ���顣 // 表示释放该目录项,并设置包含该目录项的缓冲块已修改标志,释放该高速缓冲块。 756 de->inode = 0; // Ȼ����ļ�����Ӧi�ڵ����������1�������ı�־�����¸ı�ʱ��Ϊ��ǰʱ�䡣���� // 然后把文件名对应i节点的链接数减1,置已修改标志,更新改变时间为当前时间。最后放 // �ظ�i�ڵ��Ŀ¼��i�ڵ㣬����0���ɹ�����������ļ������һ�����ӣ���i�ڵ����� // 回该i节点和目录的i节点,返回0(成功)。如果是文件的最后一个链接,即i节点链接 // ����1�����0�����Ҵ�ʱû�н��������ļ�����ô�ڵ���iput()�Ż�i�ڵ�ʱ������ // 数减1后等于0,并且此时没有进程正打开该文件,那么在调用iput()放回i节点时,该文 // ��Ҳ����ɾ�������ͷ���ռ�õ��豸�ռ䡣�μ�fs/inode.c����183�С� // 件也将被删除,并释放所占用的设备空间。参见fs/inode.c,第183行。 759
@@ -6053,16 +6053,16 @@ lang=EN-US> } 766 //// �����������ӡ� //// 建立符号链接。 // Ϊһ���Ѵ����ļ�����һ���������ӣ�Ҳ��Ϊ������ - hard link���� // 为一个已存在文件创建一个符号链接(也称为软连接 - hard link)。 // ������oldname
-- ԭ·������newname - �µ�·������ // 参数:oldname
+- 原路径名;newname - 新的路径名。 // ���أ����ɹ���0�����س����š� // 返回:若成功则返回0,否则返回出错号。 767 int sys_symlink(const char *
@@ -6096,16 +6096,16 @@ lang=EN-US> char c; 775 // ���Ȳ�����·���������Ŀ¼��i�ڵ�dir�������������ļ������䳤�ȡ����Ŀ¼�� // 首先查找新路径名的最顶层目录的i节点dir,并返回最后的文件名及其长度。如果目录的 // i�ڵ�û���ҵ����س����š������·�����в������ļ�������Ż���·����Ŀ¼�� // i节点没有找到,则返回出错号。如果新路径名中不包括文件名,则放回新路径名目录的i // �ڵ㣬���س����š����⣬����û�û������Ŀ¼��д��Ȩ�ޣ���Ҳ���ܽ������ӣ����Ƿ� // 节点,返回出错号。另外,如果用户没有在新目录中写的权限,则也不能建立连接,于是放 // ����·����Ŀ¼��i�ڵ㣬���س����š� // 回新路径名目录的i节点,返回出错号。 776 dir = EACCES; 786 } // ����������Ŀ¼ָ���豸������һ���µ�i�ڵ㣬�����ø�i�ڵ�ģʽΪ�������������Լ� // 现在我们在目录指定设备上申请一个新的i节点,并设置该i节点模式为符号链接类型以及 // ���̹涨��ģʽ�����롣�������ø�i�ڵ����ı�־�� // 进程规定的模式屏蔽码。并且设置该i节点已修改标志。 787 if (!(inode = umask); // Ϊ�˱����������·�����ַ�����Ϣ��������ҪΪ��i�ڵ�����һ�����̿飬����i�ڵ�� // 为了保存符号链接路径名字符串信息,我们需要为该i节点申请一个磁盘块,并让i节点的 // ��1��ֱ�ӿ��i_zone[0]���ڵõ�������š�Ȼ����i�ڵ����ı�־���������ʧ�� // 第1个直接块号i_zone[0]等于得到的逻辑块号。然后置i节点已修改标志。如果申请失败 // ��Żض�ӦĿ¼��i�ڵ㣻��λ�������i�ڵ����Ӽ������Żظ��µ�i�ڵ㣬����û�п� // 则放回对应目录的i节点;复位新申请的i节点链接计数;放回该新的i节点,返回没有空 // ��������˳��� // 间出错码退出。 793 if
@@ -6219,12 +6219,12 @@ lang=EN-US> } // Ȼ����豸�϶�ȡ������Ĵ��̿飨Ŀ���ǰѶ�Ӧ��ŵ����ٻ������У�������������Ż� // 然后从设备上读取新申请的磁盘块(目的是把对应块放到高速缓冲区中)。若出错,则放回 // ��ӦĿ¼��i�ڵ㣻��λ�������i�ڵ����Ӽ������Żظ��µ�i�ڵ㣬����û�пռ���� // 对应目录的i节点;复位新申请的i节点链接计数;放回该新的i节点,返回没有空间出错 // ���˳��� // 码退出。 800 if (!(name_block=ERROR; 805 } // �������ǿ��ѷ����������ַ�����������̿����ˡ��̿鳤��Ϊ1024�ֽڣ����Ĭ�Ϸ��� // 现在我们可以把符号链接名字符串放入这个盘块中了。盘块长度为1024字节,因此默认符号 // �������������Ҳֻ����1024�ֽڡ����ǰ��û��ռ��еķ����������ַ������Ƶ��̿����� // 链接名长度最大也只能是1024字节。我们把用户空间中的符号链接名字符串复制到盘块所在 // �Ļ�����У����û�������ı�־��Ϊ��ֹ�û��ṩ���ַ���û����null��β�������ڻ� // 的缓冲块中,并置缓冲块已修改标志。为防止用户提供的字符串没有以null结尾,我们在缓 // ������������һ���ֽڴ�����һ��NULL��Ȼ���ͷŸû���飬������i�ڵ��Ӧ�ļ����� // 冲块数据区最后一个字节处放上一个NULL。然后释放该缓冲块,并设置i节点对应文件中数 // �ݳ��ȵ��ڷ����������ַ������ȣ�����i�ڵ����ı�־�� // 据长度等于符号链接名字符串长度,并置i节点已修改标志。 806 i = 0; // Ȼ����������һ��·����ָ���ķ��������ļ����Ƿ��Ѿ����ڡ����Ѿ��������ܴ���ͬ�� // 然后我们搜索一下路径名指定的符号链接文件名是否已经存在。若已经存在则不能创建同名 // Ŀ¼��i�ڵ㡣�����Ӧ���������ļ����Ѿ����ڣ����ͷŰ�����Ŀ¼��Ļ������飬��λ // 目录项i节点。如果对应符号链接文件名已经存在,则释放包含该目录项的缓冲区块,复位 // �������i�ڵ����Ӽ��������Ż�Ŀ¼��i�ڵ㣬�����ļ��Ѿ����ڵij������˳��� // 新申请的i节点连接计数,并放回目录的i节点,返回文件已经存在的出错码退出。 814 bh = EEXIST; 821 } // ����������ָ��Ŀ¼��������һ��Ŀ¼����ڴ���½����������ļ�����i�ڵ�ź�Ŀ¼ // 现在我们在指定目录中新添加一个目录项,用于存放新建符号链接文件名的i节点号和目录 // �������ʧ�ܣ�������Ŀ¼��ĸ��ٻ�����ָ��ΪNULL������Ż�Ŀ¼��i�ڵ㣻������� // 名。如果失败(包含该目录项的高速缓冲区指针为NULL),则放回目录的i节点;所申请的 // i�ڵ��������Ӽ�����λ�����Żظ�i�ڵ㡣���س������˳��� // i节点引用连接计数复位,并放回该i节点。返回出错码退出。 822 bh = ENOSPC; 828 } // ��������Ŀ¼���i�ڵ��ֶε�����i�ڵ�ţ����ø��ٻ�������ı�־���ͷŸ��ٻ� // 最后令该新目录项的i节点字段等于新i节点号,并置高速缓冲块已修改标志,释放高速缓 // ��飬�Ż�Ŀ¼���µ�i�ڵ㣬���0���ɹ����� // 冲块,放回目录和新的i节点,最后返回0(成功)。 829 de->inode =
@@ -6401,16 +6401,16 @@ lang=EN-US> } 836 //// Ϊ�ļ�����һ���ļ���Ŀ¼� //// 为文件建立一个文件名目录项。 // Ϊһ���Ѵ��ڵ��ļ�����һ�������ӣ�Ҳ��ΪӲ���� - hard link���� // 为一个已存在的文件创建一个新链接(也称为硬连接 - hard link)。 // ������oldname
-- ԭ·������newname - �µ�·������ // 参数:oldname
+- 原路径名;newname - 新的路径名。 // ���أ����ɹ���0�����س����š� // 返回:若成功则返回0,否则返回出错号。 837 int sys_link(const char *
@@ -6441,13 +6441,13 @@ lang=EN-US> int namelen;<
844 // ���ȶ�ԭ�ļ���������Ч����֤����Ӧ�ô��ڲ��Ҳ���һ��Ŀ¼��������������ȡԭ�ļ�· // 首先对原文件名进行有效性验证,它应该存在并且不是一个目录名。所以我们先取原文件路 // ������Ӧ��i�ڵ�oldinode�����Ϊ0�����ʾ���������س����š����ԭ·������Ӧ���� // 径名对应的i节点oldinode。如果为0,则表示出错,返回出错号。如果原路径名对应的是 // һ��Ŀ¼������Żظ�i�ڵ㣬Ҳ���س����š� // 一个目录名,则放回该i节点,也返回出错号。 845 oldinode=EPERM; 851 } // Ȼ�������·���������Ŀ¼��i�ڵ�dir�������������ļ������䳤�ȡ����Ŀ¼�� // 然后查找新路径名的最顶层目录的i节点dir,并返回最后的文件名及其长度。如果目录的 // i�ڵ�û���ҵ�����Ż�ԭ·������i�ڵ㣬���س����š������·�����в������ļ����� // i节点没有找到,则放回原路径名的i节点,返回出错号。如果新路径名中不包括文件名, // ��Ż�ԭ·����i�ڵ����·����Ŀ¼��i�ڵ㣬���س����š� // 则放回原路径名i节点和新路径名目录的i节点,返回出错号。 852 dir = EPERM; 861 } // ���Dz��ܿ��豸����Ӳ���ӡ���������·��������Ŀ¼���豸����ԭ·�������豸�� // 我们不能跨设备建立硬链接。因此如果新路径名顶层目录的设备号与原路径名的设备号 // ��һ������Ż���·����Ŀ¼��i�ڵ��ԭ·������i�ڵ㣬���س����š����⣬����û� // 不一样,则放回新路径名目录的i节点和原路径名的i节点,返回出错号。另外,如果用户 // û������Ŀ¼��д��Ȩ�ޣ���Ҳ���ܽ������ӣ����ǷŻ���·����Ŀ¼��i�ڵ��ԭ·���� // 没有在新目录中写的权限,则也不能建立连接,于是放回新路径名目录的i节点和原路径名 // ��i�ڵ㣬���س����š� // 的i节点,返回出错号。 862 if (dir->i_dev
@@ -6570,10 +6570,10 @@ return -EACCES; 871 } // ���ڲ�ѯ����·�����Ƿ��Ѿ����ڣ����������Ҳ���ܽ������ӡ������ͷŰ������Ѵ���Ŀ // 现在查询该新路径名是否已经存在,如果存在则也不能建立链接。于是释放包含该已存在目 // ¼��ĸ��ٻ���飬�Ż���·����Ŀ¼��i�ڵ��ԭ·������i�ڵ㣬���س����š� // 录项的高速缓冲块,放回新路径名目录的i节点和原路径名的i节点,返回出错号。 872 bh = EEXIST; 878 } // �������������������ˣ�������������Ŀ¼������һ��Ŀ¼���ʧ����Żظ�Ŀ¼��i�� // 现在所有条件都满足了,于是我们在新目录中添加一个目录项。若失败则放回该目录的i节 // ���ԭ·������i�ڵ㣬���س����š������ʼ���ø�Ŀ¼���i�ڵ�ŵ���ԭ·������ // 点和原路径名的i节点,返回出错号。否则初始设置该目录项的i节点号等于原路径名的i // �ڵ�ţ����ð���������Ŀ¼��Ļ�������ı�־���ͷŸû���飬�Ż�Ŀ¼��i�ڵ㡣 // 节点号,并置包含该新添目录项的缓冲块已修改标志,释放该缓冲块,放回目录的i节点。 879 bh = brelse(bh); // �ٽ�ԭ�ڵ�����Ӽ�����1������ı�ʱ��Ϊ��ǰʱ�䣬������i�ڵ����ı�־����� // 再将原节点的链接计数加1,修改其改变时间为当前时间,并设置i节点已修改标志。最后 // �Ż�ԭ·������i�ڵ㣬������0���ɹ����� // 放回原路径名的i节点,并返回0(成功)。 889
diff --git a/Book-Lite/code-list/html/P12-7.html b/Book-Lite/code-list/html/P12-7.html
index b719dae..3430502 100644
--- a/Book-Lite/code-list/html/P12-7.html
+++ b/Book-Lite/code-list/html/P12-7.html
@@ -10,24 +10,24 @@
{font-family:Wingdings;
panose-1:5 0 0 0 0 0 0 0 0 0;}
@font-face
- {font-family:����;
+ {font-family:宋体;
panose-1:2 1 6 0 3 1 1 1 1 1;}
@font-face
- {font-family:����;
+ {font-family:黑体;
panose-1:2 1 6 9 6 1 1 1 1 1;}
@font-face
- {font-family:����;
+ {font-family:黑体;
panose-1:2 1 6 9 6 1 1 1 1 1;}
@font-face
- {font-family:����С���μ���;}
+ {font-family:方正小标宋简体;}
@font-face
- {font-family:"\@����";
+ {font-family:"\@黑体";
panose-1:2 1 6 9 6 1 1 1 1 1;}
@font-face
- {font-family:"\@����";
+ {font-family:"\@宋体";
panose-1:2 1 6 0 3 1 1 1 1 1;}
@font-face
- {font-family:"\@����С���μ���";}
+ {font-family:"\@方正小标宋简体";}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0cm;
@@ -35,9 +35,9 @@
text-align:justify;
text-justify:inter-ideograph;
font-size:10.5pt;
- font-family:����;}
+ font-family:宋体;}
h1
- {mso-style-link:"���� 1 Char";
+ {mso-style-link:"标题 1 Char";
margin-top:17.0pt;
margin-right:0cm;
margin-bottom:16.5pt;
@@ -49,7 +49,7 @@ h1
font-family:"Times New Roman","serif";
font-weight:bold;}
h2
- {mso-style-link:"���� 2 Char";
+ {mso-style-link:"标题 2 Char";
margin-top:13.0pt;
margin-right:0cm;
margin-bottom:13.0pt;
@@ -62,7 +62,7 @@ h2
font-family:"Arial","sans-serif";
font-weight:bold;}
h3
- {mso-style-link:"���� 3 Char";
+ {mso-style-link:"标题 3 Char";
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
@@ -73,7 +73,7 @@ h3
font-family:"Arial","sans-serif";
font-weight:bold;}
h4
- {mso-style-link:"���� 4 Char";
+ {mso-style-link:"标题 4 Char";
margin-top:0cm;
margin-right:0cm;
margin-bottom:0cm;
@@ -87,7 +87,7 @@ h4
font-family:"Arial","sans-serif";
font-weight:bold;}
h5
- {mso-style-link:"���� 5 Char";
+ {mso-style-link:"标题 5 Char";
margin-top:14.0pt;
margin-right:0cm;
margin-bottom:14.5pt;
@@ -101,7 +101,7 @@ h5
font-family:"Times New Roman","serif";
font-weight:bold;}
h6
- {mso-style-link:"���� 6 Char";
+ {mso-style-link:"标题 6 Char";
margin-top:12.0pt;
margin-right:0cm;
margin-bottom:3.2pt;
@@ -115,7 +115,7 @@ h6
font-family:"Arial","sans-serif";
font-weight:bold;}
p.MsoHeading7, li.MsoHeading7, div.MsoHeading7
- {mso-style-link:"���� 7 Char";
+ {mso-style-link:"标题 7 Char";
margin-top:12.0pt;
margin-right:0cm;
margin-bottom:3.2pt;
@@ -129,7 +129,7 @@ p.MsoHeading7, li.MsoHeading7, div.MsoHeading7
font-family:"Times New Roman","serif";
font-weight:bold;}
p.MsoHeading8, li.MsoHeading8, div.MsoHeading8
- {mso-style-link:"���� 8 Char";
+ {mso-style-link:"标题 8 Char";
margin-top:12.0pt;
margin-right:0cm;
margin-bottom:3.2pt;
@@ -142,7 +142,7 @@ p.MsoHeading8, li.MsoHeading8, div.MsoHeading8
font-size:12.0pt;
font-family:"Arial","sans-serif";}
p.MsoHeading9, li.MsoHeading9, div.MsoHeading9
- {mso-style-link:"���� 9 Char";
+ {mso-style-link:"标题 9 Char";
margin-top:12.0pt;
margin-right:0cm;
margin-bottom:3.2pt;
@@ -330,20 +330,20 @@ p.MsoToc9, li.MsoToc9, div.MsoToc9
font-size:9.0pt;
font-family:"Times New Roman","serif";}
p.MsoFootnoteText, li.MsoFootnoteText, div.MsoFootnoteText
- {mso-style-link:"��ע�ı� Char";
+ {mso-style-link:"脚注文本 Char";
margin:0cm;
margin-bottom:.0001pt;
layout-grid-mode:char;
font-size:9.0pt;
font-family:"Times New Roman","serif";}
p.MsoCommentText, li.MsoCommentText, div.MsoCommentText
- {mso-style-link:"��ע���� Char";
+ {mso-style-link:"批注文字 Char";
margin:0cm;
margin-bottom:.0001pt;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.MsoHeader, li.MsoHeader, div.MsoHeader
- {mso-style-link:"ҳü Char";
+ {mso-style-link:"页眉 Char";
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
@@ -353,14 +353,14 @@ p.MsoHeader, li.MsoHeader, div.MsoHeader
font-size:9.0pt;
font-family:"Times New Roman","serif";}
p.MsoFooter, li.MsoFooter, div.MsoFooter
- {mso-style-link:"ҳ�� Char";
+ {mso-style-link:"页脚 Char";
margin:0cm;
margin-bottom:.0001pt;
layout-grid-mode:char;
font-size:9.0pt;
font-family:"Times New Roman","serif";}
p.MsoIndexHeading, li.MsoIndexHeading, div.MsoIndexHeading
- {mso-style-name:"��������\,������Ŀ\,������Ŀ1\,������Ŀ2";
+ {mso-style-name:"索引标题\,索引类目\,索引类目1\,索引类目2";
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
@@ -411,7 +411,7 @@ p.MsoList4, li.MsoList4, div.MsoList4
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.MsoDate, li.MsoDate, div.MsoDate
- {mso-style-link:"���� Char";
+ {mso-style-link:"日期 Char";
margin-top:0cm;
margin-right:0cm;
margin-bottom:0cm;
@@ -422,36 +422,36 @@ p.MsoDate, li.MsoDate, div.MsoDate
font-size:10.0pt;
font-family:"Times New Roman","serif";}
a:link, span.MsoHyperlink
- {mso-style-name:"������\,��������";
+ {mso-style-name:"超链接\,超级链接";
color:blue;
text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
{color:purple;
text-decoration:underline;}
p
- {mso-style-name:"��ͨ\(��վ\)\,��ͨ \(Web\)\,��ͨ \(Web\)1\,��ͨ \(Web\)2\,��ͨ \(Web\)3";
+ {mso-style-name:"普通\(网站\)\,普通 \(Web\)\,普通 \(Web\)1\,普通 \(Web\)2\,普通 \(Web\)3";
margin-right:0cm;
margin-left:0cm;
font-size:12.0pt;
font-family:"Times New Roman","serif";}
pre
- {mso-style-name:"HTML Ԥ���ʽ\,HTML Ԥ�ȸ�ʽ��\,HTML Ԥ�ȸ�ʽ��1\,HTML Ԥ�ȸ�ʽ��2\,HTML Ԥ�ȸ�ʽ��3";
- mso-style-link:"HTML Ԥ���ʽ Char\,HTML Ԥ�ȸ�ʽ�� Char\,HTML Ԥ�ȸ�ʽ��1 Char\,HTML Ԥ�ȸ�ʽ��2 Char\,HTML Ԥ�ȸ�ʽ��3 Char";
+ {mso-style-name:"HTML 预设格式\,HTML 预先格式化\,HTML 预先格式化1\,HTML 预先格式化2\,HTML 预先格式化3";
+ mso-style-link:"HTML 预设格式 Char\,HTML 预先格式化 Char\,HTML 预先格式化1 Char\,HTML 预先格式化2 Char\,HTML 预先格式化3 Char";
margin:0cm;
margin-bottom:.0001pt;
font-size:12.0pt;
font-family:"Times New Roman","serif";}
tt
- {font-family:����;}
+ {font-family:黑体;}
p.MsoCommentSubject, li.MsoCommentSubject, div.MsoCommentSubject
- {mso-style-link:"��ע���� Char";
+ {mso-style-link:"批注主题 Char";
margin:0cm;
margin-bottom:.0001pt;
font-size:10.0pt;
font-family:"Times New Roman","serif";
font-weight:bold;}
p.MsoAcetate, li.MsoAcetate, div.MsoAcetate
- {mso-style-link:"��ע���ı� Char";
+ {mso-style-link:"批注框文本 Char";
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
@@ -459,7 +459,7 @@ p.MsoAcetate, li.MsoAcetate, div.MsoAcetate
font-size:9.0pt;
font-family:"Times New Roman","serif";}
p.1, li.1, div.1
- {mso-style-name:��ʽ1;
+ {mso-style-name:样式1;
margin-top:0cm;
margin-right:0cm;
margin-bottom:0cm;
@@ -470,30 +470,30 @@ p.1, li.1, div.1
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.a, li.a, div.a
- {mso-style-name:�������;
- mso-style-link:"������� Char";
+ {mso-style-name:代码程序;
+ mso-style-link:"代码程序 Char";
margin:0cm;
margin-bottom:.0001pt;
font-size:10.0pt;
- font-family:����;}
+ font-family:宋体;}
span.Char
- {mso-style-name:"������� Char";
- mso-style-link:�������;
- font-family:����;}
+ {mso-style-name:"代码程序 Char";
+ mso-style-link:代码程序;
+ font-family:宋体;}
p.a0, li.a0, div.a0
- {mso-style-name:ͼ˵��;
- mso-style-link:"ͼ˵�� Char";
+ {mso-style-name:图说明;
+ mso-style-link:"图说明 Char";
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
span.Char0
- {mso-style-name:"ͼ˵�� Char";
- mso-style-link:ͼ˵��;
- font-family:����;}
+ {mso-style-name:"图说明 Char";
+ mso-style-link:图说明;
+ font-family:宋体;}
p.0, li.0, div.0
- {mso-style-name:����0;
+ {mso-style-name:封面0;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
@@ -501,7 +501,7 @@ p.0, li.0, div.0
font-family:"Times New Roman","serif";
font-weight:bold;}
p.10, li.10, div.10
- {mso-style-name:����1;
+ {mso-style-name:封面1;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
@@ -509,25 +509,25 @@ p.10, li.10, div.10
font-family:"Times New Roman","serif";
font-weight:bold;}
p.11, li.11, div.11
- {mso-style-name:�DZ���1;
+ {mso-style-name:非标题1;
margin-top:7.8pt;
margin-right:0cm;
margin-bottom:7.8pt;
margin-left:0cm;
text-align:center;
font-size:22.0pt;
- font-family:����;
+ font-family:宋体;
font-weight:bold;}
p.a1, li.a1, div.a1
- {mso-style-name:�ı�����;
+ {mso-style-name:文本居中;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.3CharChar, li.3CharChar, div.3CharChar
- {mso-style-name:"ͼ������3 Char Char";
- mso-style-link:"ͼ������3 Char Char Char";
+ {mso-style-name:"图中文字3 Char Char";
+ mso-style-link:"图中文字3 Char Char Char";
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
@@ -535,11 +535,11 @@ p.3CharChar, li.3CharChar, div.3CharChar
font-size:8.0pt;
font-family:"Times New Roman","serif";}
span.3CharCharChar
- {mso-style-name:"ͼ������3 Char Char Char";
- mso-style-link:"ͼ������3 Char Char";
- font-family:����;}
+ {mso-style-name:"图中文字3 Char Char Char";
+ mso-style-link:"图中文字3 Char Char";
+ font-family:宋体;}
p.post, li.post, div.post
- {mso-style-name:�ʼ�post;
+ {mso-style-name:邮件post;
margin:0cm;
margin-bottom:.0001pt;
text-align:right;
@@ -547,7 +547,7 @@ p.post, li.post, div.post
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.3, li.3, div.3
- {mso-style-name:ͼ������3;
+ {mso-style-name:图中字体3;
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
@@ -555,44 +555,44 @@ p.3, li.3, div.3
font-size:10.0pt;
font-family:"Times New Roman","serif";}
span.3CharChar1CharCharChar
- {mso-style-name:"ͼ������3 Char Char1 Char Char Char";
- font-family:����;}
+ {mso-style-name:"图中文字3 Char Char1 Char Char Char";
+ font-family:宋体;}
span.3CharChar1CharChar
- {mso-style-name:"ͼ������3 Char Char1 Char Char";
- font-family:����;}
+ {mso-style-name:"图中文字3 Char Char1 Char Char";
+ font-family:宋体;}
p.5Char, li.5Char, div.5Char
- {mso-style-name:"ͼ������5�� Char";
- mso-style-link:"ͼ������5�� Char Char";
+ {mso-style-name:"图中文字5号 Char";
+ mso-style-link:"图中文字5号 Char Char";
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
span.5CharChar
- {mso-style-name:"ͼ������5�� Char Char";
- mso-style-link:"ͼ������5�� Char";
- font-family:����;}
+ {mso-style-name:"图中文字5号 Char Char";
+ mso-style-link:"图中文字5号 Char";
+ font-family:宋体;}
p.5CharChar0, li.5CharChar0, div.5CharChar0
- {mso-style-name:"ͼ������С5�� Char Char";
- mso-style-link:"ͼ������С5�� Char Char Char";
+ {mso-style-name:"图中文字小5号 Char Char";
+ mso-style-link:"图中文字小5号 Char Char Char";
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:9.0pt;
font-family:"Times New Roman","serif";}
span.5CharCharChar
- {mso-style-name:"ͼ������С5�� Char Char Char";
- mso-style-link:"ͼ������С5�� Char Char";
- font-family:����;}
+ {mso-style-name:"图中文字小5号 Char Char Char";
+ mso-style-link:"图中文字小5号 Char Char";
+ font-family:宋体;}
p.5Char0, li.5Char0, div.5Char0
- {mso-style-name:"ͼ������С5�� Char";
+ {mso-style-name:"图中文字小5号 Char";
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:9.0pt;
font-family:"Times New Roman","serif";}
p.5, li.5, div.5
- {mso-style-name:ͼ������С5��;
+ {mso-style-name:图中文字小5号;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
@@ -600,28 +600,28 @@ p.5, li.5, div.5
font-size:9.0pt;
font-family:"Times New Roman","serif";}
p.2, li.2, div.2
- {mso-style-name:�������2;
+ {mso-style-name:代码程序2;
margin:0cm;
margin-bottom:.0001pt;
font-size:10.0pt;
- font-family:����;}
+ font-family:宋体;}
p.20, li.20, div.20
- {mso-style-name:ͼ˵��2;
+ {mso-style-name:图说明2;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.21, li.21, div.21
- {mso-style-name:�ı�����2;
+ {mso-style-name:文本居中2;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.3CharCharCharCharChar, li.3CharCharCharCharChar, div.3CharCharCharCharChar
- {mso-style-name:"ͼ������3 Char Char Char Char Char";
- mso-style-link:"ͼ������3 Char Char Char Char Char Char";
+ {mso-style-name:"图中文字3 Char Char Char Char Char";
+ mso-style-link:"图中文字3 Char Char Char Char Char Char";
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
@@ -629,18 +629,18 @@ p.3CharCharCharCharChar, li.3CharCharCharCharChar, div.3CharCharCharCharChar
font-size:8.0pt;
font-family:"Times New Roman","serif";}
span.3CharCharCharCharCharChar
- {mso-style-name:"ͼ������3 Char Char Char Char Char Char";
- mso-style-link:"ͼ������3 Char Char Char Char Char";
- font-family:����;}
+ {mso-style-name:"图中文字3 Char Char Char Char Char Char";
+ mso-style-link:"图中文字3 Char Char Char Char Char";
+ font-family:宋体;}
p.a2, li.a2, div.a2
- {mso-style-name:ͼ����;
+ {mso-style-name:图居中;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.110, li.110, div.110
- {mso-style-name:"��ʽ ���� 1 + ����1";
+ {mso-style-name:"样式 标题 1 + 居中1";
margin-right:0cm;
margin-left:0cm;
text-align:center;
@@ -649,32 +649,32 @@ p.110, li.110, div.110
font-family:"Times New Roman","serif";
font-weight:bold;}
span.1Char
- {mso-style-name:"���� 1 Char";
- mso-style-link:"���� 1";
+ {mso-style-name:"标题 1 Char";
+ mso-style-link:"标题 1";
font-weight:bold;}
p.22, li.22, div.22
- {mso-style-name:"��ʽ �б� 2 + ����";
+ {mso-style-name:"样式 列表 2 + 居中";
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.23, li.23, div.23
- {mso-style-name:�б�2;
+ {mso-style-name:列表2;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.50, li.50, div.50
- {mso-style-name:ͼ������5��;
+ {mso-style-name:图中文字5号;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.111, li.111, div.111
- {mso-style-name:��ʽ11;
+ {mso-style-name:样式11;
margin-top:0cm;
margin-right:0cm;
margin-bottom:0cm;
@@ -685,20 +685,20 @@ p.111, li.111, div.111
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.12, li.12, div.12
- {mso-style-name:�������1;
+ {mso-style-name:代码程序1;
margin:0cm;
margin-bottom:.0001pt;
font-size:10.0pt;
- font-family:����;}
+ font-family:宋体;}
p.13, li.13, div.13
- {mso-style-name:ͼ˵��1;
+ {mso-style-name:图说明1;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.01, li.01, div.01
- {mso-style-name:����01;
+ {mso-style-name:封面01;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
@@ -706,7 +706,7 @@ p.01, li.01, div.01
font-family:"Times New Roman","serif";
font-weight:bold;}
p.112, li.112, div.112
- {mso-style-name:����11;
+ {mso-style-name:封面11;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
@@ -714,24 +714,24 @@ p.112, li.112, div.112
font-family:"Times New Roman","serif";
font-weight:bold;}
p.113, li.113, div.113
- {mso-style-name:�DZ���11;
+ {mso-style-name:非标题11;
margin-top:7.8pt;
margin-right:0cm;
margin-bottom:7.8pt;
margin-left:0cm;
text-align:center;
font-size:22.0pt;
- font-family:����;
+ font-family:宋体;
font-weight:bold;}
p.14, li.14, div.14
- {mso-style-name:�ı�����1;
+ {mso-style-name:文本居中1;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.3Char1, li.3Char1, div.3Char1
- {mso-style-name:"ͼ������3 Char1";
+ {mso-style-name:"图中文字3 Char1";
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
@@ -739,7 +739,7 @@ p.3Char1, li.3Char1, div.3Char1
font-size:8.0pt;
font-family:"Times New Roman","serif";}
p.post1, li.post1, div.post1
- {mso-style-name:�ʼ�post1;
+ {mso-style-name:邮件post1;
margin:0cm;
margin-bottom:.0001pt;
text-align:right;
@@ -747,7 +747,7 @@ p.post1, li.post1, div.post1
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.31, li.31, div.31
- {mso-style-name:ͼ������31;
+ {mso-style-name:图中字体31;
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
@@ -755,35 +755,35 @@ p.31, li.31, div.31
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.5Char1, li.5Char1, div.5Char1
- {mso-style-name:"ͼ������5�� Char1";
+ {mso-style-name:"图中文字5号 Char1";
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.5CharChar1, li.5CharChar1, div.5CharChar1
- {mso-style-name:"ͼ������С5�� Char Char1";
+ {mso-style-name:"图中文字小5号 Char Char1";
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:9.0pt;
font-family:"Times New Roman","serif";}
p.5Char10, li.5Char10, div.5Char10
- {mso-style-name:"ͼ������С5�� Char1";
+ {mso-style-name:"图中文字小5号 Char1";
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:9.0pt;
font-family:"Times New Roman","serif";}
p.51, li.51, div.51
- {mso-style-name:ͼ������С5��1;
+ {mso-style-name:图中文字小5号1;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:9.0pt;
font-family:"Times New Roman","serif";}
p.120, li.120, div.120
- {mso-style-name:��ʽ12;
+ {mso-style-name:样式12;
margin-top:0cm;
margin-right:0cm;
margin-bottom:0cm;
@@ -794,7 +794,7 @@ p.120, li.120, div.120
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.02, li.02, div.02
- {mso-style-name:����02;
+ {mso-style-name:封面02;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
@@ -802,7 +802,7 @@ p.02, li.02, div.02
font-family:"Times New Roman","serif";
font-weight:bold;}
p.121, li.121, div.121
- {mso-style-name:����12;
+ {mso-style-name:封面12;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
@@ -810,17 +810,17 @@ p.121, li.121, div.121
font-family:"Times New Roman","serif";
font-weight:bold;}
p.122, li.122, div.122
- {mso-style-name:�DZ���12;
+ {mso-style-name:非标题12;
margin-top:7.8pt;
margin-right:0cm;
margin-bottom:7.8pt;
margin-left:0cm;
text-align:center;
font-size:22.0pt;
- font-family:����;
+ font-family:宋体;
font-weight:bold;}
p.3Char2, li.3Char2, div.3Char2
- {mso-style-name:"ͼ������3 Char2";
+ {mso-style-name:"图中文字3 Char2";
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
@@ -828,7 +828,7 @@ p.3Char2, li.3Char2, div.3Char2
font-size:8.0pt;
font-family:"Times New Roman","serif";}
p.post2, li.post2, div.post2
- {mso-style-name:�ʼ�post2;
+ {mso-style-name:邮件post2;
margin:0cm;
margin-bottom:.0001pt;
text-align:right;
@@ -836,7 +836,7 @@ p.post2, li.post2, div.post2
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.32, li.32, div.32
- {mso-style-name:ͼ������32;
+ {mso-style-name:图中字体32;
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
@@ -844,21 +844,21 @@ p.32, li.32, div.32
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.5Char2, li.5Char2, div.5Char2
- {mso-style-name:"ͼ������С5�� Char2";
+ {mso-style-name:"图中文字小5号 Char2";
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:9.0pt;
font-family:"Times New Roman","serif";}
p.52, li.52, div.52
- {mso-style-name:ͼ������С5��2;
+ {mso-style-name:图中文字小5号2;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:9.0pt;
font-family:"Times New Roman","serif";}
p.3CharCharCharChar, li.3CharCharCharChar, div.3CharCharCharChar
- {mso-style-name:"ͼ������3 Char Char Char Char";
+ {mso-style-name:"图中文字3 Char Char Char Char";
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
@@ -866,7 +866,7 @@ p.3CharCharCharChar, li.3CharCharCharChar, div.3CharCharCharChar
font-size:8.0pt;
font-family:"Times New Roman","serif";}
p.130, li.130, div.130
- {mso-style-name:��ʽ13;
+ {mso-style-name:样式13;
margin-top:0cm;
margin-right:0cm;
margin-bottom:0cm;
@@ -877,13 +877,13 @@ p.130, li.130, div.130
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.30, li.30, div.30
- {mso-style-name:�������3;
+ {mso-style-name:代码程序3;
margin:0cm;
margin-bottom:.0001pt;
font-size:10.0pt;
- font-family:����;}
+ font-family:宋体;}
p.03, li.03, div.03
- {mso-style-name:����03;
+ {mso-style-name:封面03;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
@@ -891,7 +891,7 @@ p.03, li.03, div.03
font-family:"Times New Roman","serif";
font-weight:bold;}
p.131, li.131, div.131
- {mso-style-name:����13;
+ {mso-style-name:封面13;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
@@ -899,24 +899,24 @@ p.131, li.131, div.131
font-family:"Times New Roman","serif";
font-weight:bold;}
p.132, li.132, div.132
- {mso-style-name:�DZ���13;
+ {mso-style-name:非标题13;
margin-top:7.8pt;
margin-right:0cm;
margin-bottom:7.8pt;
margin-left:0cm;
text-align:center;
font-size:22.0pt;
- font-family:����;
+ font-family:宋体;
font-weight:bold;}
p.33, li.33, div.33
- {mso-style-name:�ı�����3;
+ {mso-style-name:文本居中3;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.3Char3, li.3Char3, div.3Char3
- {mso-style-name:"ͼ������3 Char3";
+ {mso-style-name:"图中文字3 Char3";
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
@@ -924,7 +924,7 @@ p.3Char3, li.3Char3, div.3Char3
font-size:8.0pt;
font-family:"Times New Roman","serif";}
p.post3, li.post3, div.post3
- {mso-style-name:�ʼ�post3;
+ {mso-style-name:邮件post3;
margin:0cm;
margin-bottom:.0001pt;
text-align:right;
@@ -932,7 +932,7 @@ p.post3, li.post3, div.post3
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.330, li.330, div.330
- {mso-style-name:ͼ������33;
+ {mso-style-name:图中字体33;
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
@@ -940,36 +940,36 @@ p.330, li.330, div.330
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.5Char20, li.5Char20, div.5Char20
- {mso-style-name:"ͼ������5�� Char2";
+ {mso-style-name:"图中文字5号 Char2";
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.5CharChar2, li.5CharChar2, div.5CharChar2
- {mso-style-name:"ͼ������С5�� Char Char2";
+ {mso-style-name:"图中文字小5号 Char Char2";
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:9.0pt;
font-family:"Times New Roman","serif";}
p.5Char3, li.5Char3, div.5Char3
- {mso-style-name:"ͼ������С5�� Char3";
+ {mso-style-name:"图中文字小5号 Char3";
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:9.0pt;
font-family:"Times New Roman","serif";}
p.53, li.53, div.53
- {mso-style-name:ͼ������С5��3;
+ {mso-style-name:图中文字小5号3;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:9.0pt;
font-family:"Times New Roman","serif";}
p.3Char, li.3Char, div.3Char
- {mso-style-name:"ͼ������3 Char";
- mso-style-link:"ͼ������3 Char Char5";
+ {mso-style-name:"图中文字3 Char";
+ mso-style-link:"图中文字3 Char Char5";
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
@@ -977,11 +977,11 @@ p.3Char, li.3Char, div.3Char
font-size:8.0pt;
font-family:"Times New Roman","serif";}
span.3CharChar5
- {mso-style-name:"ͼ������3 Char Char5";
- mso-style-link:"ͼ������3 Char";
- font-family:����;}
+ {mso-style-name:"图中文字3 Char Char5";
+ mso-style-link:"图中文字3 Char";
+ font-family:宋体;}
p.54, li.54, div.54
- {mso-style-name:ͼ������С5����;
+ {mso-style-name:图中文字小5紧密;
margin:0cm;
margin-bottom:.0001pt;
line-height:9.0pt;
@@ -989,7 +989,7 @@ p.54, li.54, div.54
font-size:9.0pt;
font-family:"Times New Roman","serif";}
p.24, li.24, div.24
- {mso-style-name:����2�Ŵ�����;
+ {mso-style-name:居中2号粗宋体;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
@@ -997,7 +997,7 @@ p.24, li.24, div.24
font-family:"Times New Roman","serif";
font-weight:bold;}
p.15, li.15, div.15
- {mso-style-name:"��ʽ ���� 1 + ����";
+ {mso-style-name:"样式 标题 1 + 居中";
margin-top:17.0pt;
margin-right:0cm;
margin-bottom:16.5pt;
@@ -1008,7 +1008,7 @@ p.15, li.15, div.15
font-family:"Times New Roman","serif";
font-weight:bold;}
p.25, li.25, div.25
- {mso-style-name:"��ʽ ���� 2 + �о�\: �����о�";
+ {mso-style-name:"样式 标题 2 + 行距\: 单倍行距";
margin-top:13.0pt;
margin-right:0cm;
margin-bottom:13.0pt;
@@ -1021,33 +1021,33 @@ p.25, li.25, div.25
font-family:"Arial","sans-serif";
font-weight:bold;}
span.2Char
- {mso-style-name:"���� 2 Char";
- mso-style-link:"���� 2";
+ {mso-style-name:"标题 2 Char";
+ mso-style-link:"标题 2";
font-family:"Arial","sans-serif";
font-weight:bold;}
p.34, li.34, div.34
- {mso-style-name:�б�3;
+ {mso-style-name:列表3;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.35, li.35, div.35
- {mso-style-name:��3;
+ {mso-style-name:表3;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.4, li.4, div.4
- {mso-style-name:ͼ˵��4;
+ {mso-style-name:图说明4;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.40, li.40, div.40
- {mso-style-name:�б�4;
+ {mso-style-name:列表4;
margin-top:0cm;
margin-right:0cm;
margin-bottom:0cm;
@@ -1058,166 +1058,166 @@ p.40, li.40, div.40
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.41, li.41, div.41
- {mso-style-name:��4;
+ {mso-style-name:表4;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.55, li.55, div.55
- {mso-style-name:ͼ˵��5;
+ {mso-style-name:图说明5;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.56, li.56, div.56
- {mso-style-name:�б�5;
+ {mso-style-name:列表5;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.57, li.57, div.57
- {mso-style-name:��5;
+ {mso-style-name:表5;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.6, li.6, div.6
- {mso-style-name:�б�6;
+ {mso-style-name:列表6;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.60, li.60, div.60
- {mso-style-name:��6;
+ {mso-style-name:表6;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.61, li.61, div.61
- {mso-style-name:ͼ˵��6;
+ {mso-style-name:图说明6;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.7, li.7, div.7
- {mso-style-name:�б�7;
+ {mso-style-name:列表7;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.70, li.70, div.70
- {mso-style-name:ͼ˵��7;
+ {mso-style-name:图说明7;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.71, li.71, div.71
- {mso-style-name:��7;
+ {mso-style-name:表7;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.8, li.8, div.8
- {mso-style-name:�б�8;
+ {mso-style-name:列表8;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.9, li.9, div.9
- {mso-style-name:�б�9;
+ {mso-style-name:列表9;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.90, li.90, div.90
- {mso-style-name:ͼ˵��9;
+ {mso-style-name:图说明9;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.100, li.100, div.100
- {mso-style-name:�б�10;
+ {mso-style-name:列表10;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.101, li.101, div.101
- {mso-style-name:ͼ˵��10;
+ {mso-style-name:图说明10;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.114, li.114, div.114
- {mso-style-name:�б�11;
+ {mso-style-name:列表11;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.115, li.115, div.115
- {mso-style-name:ͼ˵��11;
+ {mso-style-name:图说明11;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.116, li.116, div.116
- {mso-style-name:��11;
+ {mso-style-name:表11;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.123, li.123, div.123
- {mso-style-name:�б�12;
+ {mso-style-name:列表12;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.124, li.124, div.124
- {mso-style-name:ͼ˵��12;
+ {mso-style-name:图说明12;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.133, li.133, div.133
- {mso-style-name:ͼ˵��13;
- mso-style-link:"ͼ˵��13 Char";
+ {mso-style-name:图说明13;
+ mso-style-link:"图说明13 Char";
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
span.13Char
- {mso-style-name:"ͼ˵��13 Char";
- mso-style-link:ͼ˵��13;
- font-family:����;}
+ {mso-style-name:"图说明13 Char";
+ mso-style-link:图说明13;
+ font-family:宋体;}
p.134, li.134, div.134
- {mso-style-name:�б�13;
+ {mso-style-name:列表13;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.26, li.26, div.26
- {mso-style-name:��¼2;
+ {mso-style-name:附录2;
margin-top:13.0pt;
margin-right:0cm;
margin-bottom:13.0pt;
@@ -1229,7 +1229,7 @@ p.26, li.26, div.26
font-family:"Arial","sans-serif";
font-weight:bold;}
p.36, li.36, div.36
- {mso-style-name:��¼3;
+ {mso-style-name:附录3;
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
@@ -1239,12 +1239,12 @@ p.36, li.36, div.36
font-family:"Arial","sans-serif";
font-weight:bold;}
span.3Char0
- {mso-style-name:"���� 3 Char";
- mso-style-link:"���� 3";
+ {mso-style-name:"标题 3 Char";
+ mso-style-link:"标题 3";
font-family:"Arial","sans-serif";
font-weight:bold;}
p.16, li.16, div.16
- {mso-style-name:��¼1;
+ {mso-style-name:附录1;
margin-top:17.0pt;
margin-right:0cm;
margin-bottom:16.5pt;
@@ -1255,14 +1255,14 @@ p.16, li.16, div.16
font-family:"Times New Roman","serif";
font-weight:bold;}
p.17, li.17, div.17
- {mso-style-name:��¼��1;
+ {mso-style-name:附录表1;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.42, li.42, div.42
- {mso-style-name:��¼4;
+ {mso-style-name:附录4;
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
@@ -1272,19 +1272,19 @@ p.42, li.42, div.42
font-family:"Arial","sans-serif";
font-weight:bold;}
span.4Char
- {mso-style-name:"���� 4 Char";
- mso-style-link:"���� 4";
+ {mso-style-name:"标题 4 Char";
+ mso-style-link:"标题 4";
font-family:"Arial","sans-serif";
font-weight:bold;}
p.a3, li.a3, div.a3
- {mso-style-name:��¼ͼ˵��;
+ {mso-style-name:附录图说明;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.27, li.27, div.27
- {mso-style-name:�����2;
+ {mso-style-name:序标题2;
margin-top:13.0pt;
margin-right:0cm;
margin-bottom:13.0pt;
@@ -1297,7 +1297,7 @@ p.27, li.27, div.27
font-family:"Arial","sans-serif";
font-weight:bold;}
p.a4, li.a4, div.a4
- {mso-style-name:�����;
+ {mso-style-name:参考标题;
margin-top:7.8pt;
margin-right:0cm;
margin-bottom:7.8pt;
@@ -1308,7 +1308,7 @@ p.a4, li.a4, div.a4
font-family:"Times New Roman","serif";
font-weight:bold;}
p.18, li.18, div.18
- {mso-style-name:��������1;
+ {mso-style-name:索引标题1;
margin-top:7.8pt;
margin-right:0cm;
margin-bottom:7.8pt;
@@ -1319,7 +1319,7 @@ p.18, li.18, div.18
font-family:"Times New Roman","serif";
font-weight:bold;}
p.19, li.19, div.19
- {mso-style-name:�б�1;
+ {mso-style-name:列表1;
margin-top:0cm;
margin-right:0cm;
margin-bottom:0cm;
@@ -1330,7 +1330,7 @@ p.19, li.19, div.19
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.1a, li.1a, div.1a
- {mso-style-name:��1;
+ {mso-style-name:表1;
margin-top:0cm;
margin-right:0cm;
margin-bottom:0cm;
@@ -1341,14 +1341,14 @@ p.1a, li.1a, div.1a
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.37, li.37, div.37
- {mso-style-name:ͼ˵��3;
+ {mso-style-name:图说明3;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.62, li.62, div.62
- {mso-style-name:��������6��;
+ {mso-style-name:表中字体6号;
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
@@ -1357,8 +1357,8 @@ p.62, li.62, div.62
font-size:7.5pt;
font-family:"Times New Roman","serif";}
p.a5, li.a5, div.a5
- {mso-style-name:���Ĵ���;
- mso-style-link:"���Ĵ��� Char";
+ {mso-style-name:正文代码;
+ mso-style-link:"正文代码 Char";
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
@@ -1366,11 +1366,11 @@ p.a5, li.a5, div.a5
font-size:10.0pt;
font-family:"Times New Roman","serif";}
span.Char1
- {mso-style-name:"���Ĵ��� Char";
- mso-style-link:���Ĵ���;
- font-family:����;}
+ {mso-style-name:"正文代码 Char";
+ mso-style-link:正文代码;
+ font-family:宋体;}
p.43, li.43, div.43
- {mso-style-name:"��ʽ ���� 4 +";
+ {mso-style-name:"样式 标题 4 +";
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
@@ -1380,7 +1380,7 @@ p.43, li.43, div.43
font-family:"Arial","sans-serif";
font-weight:bold;}
p.140, li.140, div.140
- {mso-style-name:��14;
+ {mso-style-name:表14;
margin-top:0cm;
margin-right:0cm;
margin-bottom:0cm;
@@ -1391,8 +1391,8 @@ p.140, li.140, div.140
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.141, li.141, div.141
- {mso-style-name:ͼ˵��14;
- mso-style-link:"ͼ˵��14 Char";
+ {mso-style-name:图说明14;
+ mso-style-link:"图说明14 Char";
margin-top:0cm;
margin-right:0cm;
margin-bottom:0cm;
@@ -1403,11 +1403,11 @@ p.141, li.141, div.141
font-size:10.0pt;
font-family:"Times New Roman","serif";}
span.14Char
- {mso-style-name:"ͼ˵��14 Char";
- mso-style-link:ͼ˵��14;
- font-family:����;}
+ {mso-style-name:"图说明14 Char";
+ mso-style-link:图说明14;
+ font-family:宋体;}
p.a6, li.a6, div.a6
- {mso-style-name:�ļ�Ŀ¼��;
+ {mso-style-name:文件目录表;
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
@@ -1415,8 +1415,8 @@ p.a6, li.a6, div.a6
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.a7, li.a7, div.a7
- {mso-style-name:"��ʽ ���� +";
- mso-style-link:"��ʽ ���� + Char";
+ {mso-style-name:"样式 正文 +";
+ mso-style-link:"样式 正文 + Char";
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
@@ -1424,39 +1424,39 @@ p.a7, li.a7, div.a7
font-size:10.0pt;
font-family:"Times New Roman","serif";}
span.Char2
- {mso-style-name:"��ʽ ���� + Char";
- mso-style-link:"��ʽ ���� +";
+ {mso-style-name:"样式 正文 + Char";
+ mso-style-link:"样式 正文 +";
font-family:"Times New Roman","serif";}
p.a8, li.a8, div.a8
- {mso-style-name:������ע;
+ {mso-style-name:表格题注;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.5pt;
- font-family:����;}
+ font-family:宋体;}
p.a9, li.a9, div.a9
- {mso-style-name:�б���ע;
+ {mso-style-name:列表题注;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.5pt;
font-family:"Arial","sans-serif";}
p.aa, li.aa, div.aa
- {mso-style-name:ͼ��ע;
+ {mso-style-name:图题注;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.5pt;
font-family:"Arial","sans-serif";}
p.ab, li.ab, div.ab
- {mso-style-name:������ע;
+ {mso-style-name:程序题注;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.5pt;
font-family:"Arial","sans-serif";}
p.ac, li.ac, div.ac
- {mso-style-name:��������;
+ {mso-style-name:框中文字;
margin-top:0cm;
margin-right:21.0pt;
margin-bottom:0cm;
@@ -1469,7 +1469,7 @@ p.ac, li.ac, div.ac
font-size:9.0pt;
font-family:"Times New Roman","serif";}
p.125, li.125, div.125
- {mso-style-name:"��ʽ ���� 1 + ����2";
+ {mso-style-name:"样式 标题 1 + 居中2";
margin-top:17.0pt;
margin-right:0cm;
margin-bottom:16.5pt;
@@ -1480,14 +1480,14 @@ p.125, li.125, div.125
font-family:"Times New Roman","serif";
font-weight:bold;}
p.ad, li.ad, div.ad
- {mso-style-name:"��ʽ ��ע + ���� ��� ����";
+ {mso-style-name:"样式 题注 + 宋体 五号 居中";
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.5pt;
- font-family:����;}
+ font-family:黑体;}
p.1b, li.1b, div.1b
- {mso-style-name:�����1;
+ {mso-style-name:序标题1;
margin-top:17.0pt;
margin-right:0cm;
margin-bottom:16.5pt;
@@ -1498,16 +1498,16 @@ p.1b, li.1b, div.1b
font-family:"Times New Roman","serif";
font-weight:bold;}
p.38, li.38, div.38
- {mso-style-name:�����3;
+ {mso-style-name:序标题3;
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
text-justify:inter-ideograph;
page-break-after:avoid;
font-size:12.0pt;
- font-family:����С���μ���;}
+ font-family:方正小标宋简体;}
p.63, li.63, div.63
- {mso-style-name:��������6��;
+ {mso-style-name:表中文字6号;
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
@@ -1515,7 +1515,7 @@ p.63, li.63, div.63
font-size:7.5pt;
font-family:"Times New Roman","serif";}
p.64, li.64, div.64
- {mso-style-name:ͼ������6�������;
+ {mso-style-name:图中文字6号左对齐;
margin:0cm;
margin-bottom:.0001pt;
line-height:10.0pt;
@@ -1523,8 +1523,8 @@ p.64, li.64, div.64
font-size:7.5pt;
font-family:"Times New Roman","serif";}
p.65, li.65, div.65
- {mso-style-name:ͼ������6��;
- mso-style-link:"ͼ������6�� Char";
+ {mso-style-name:图中文字6号;
+ mso-style-link:"图中文字6号 Char";
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
@@ -1533,11 +1533,11 @@ p.65, li.65, div.65
font-size:7.5pt;
font-family:"Times New Roman","serif";}
span.6Char
- {mso-style-name:"ͼ������6�� Char";
- mso-style-link:ͼ������6��;
- font-family:����;}
+ {mso-style-name:"图中文字6号 Char";
+ mso-style-link:图中文字6号;
+ font-family:宋体;}
p.ae, li.ae, div.ae
- {mso-style-name:ͼ��;
+ {mso-style-name:图标;
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
@@ -1545,7 +1545,7 @@ p.ae, li.ae, div.ae
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.28, li.28, div.28
- {mso-style-name:ͼ��2;
+ {mso-style-name:图标2;
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
@@ -1553,7 +1553,7 @@ p.28, li.28, div.28
font-size:10.0pt;
font-family:"Times New Roman","serif";}
p.af, li.af, div.af
- {mso-style-name:ϰ�����;
+ {mso-style-name:习题标题;
margin-top:6.0pt;
margin-right:0cm;
margin-bottom:0cm;
@@ -1563,9 +1563,9 @@ p.af, li.af, div.af
text-justify:inter-ideograph;
page-break-after:avoid;
font-size:14.0pt;
- font-family:����;}
+ font-family:黑体;}
p.1c, li.1c, div.1c
- {mso-style-name:���ֱ��1;
+ {mso-style-name:部分编号1;
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
@@ -1573,14 +1573,14 @@ p.1c, li.1c, div.1c
font-size:16.0pt;
font-family:"Times New Roman","serif";}
p.af0, li.af0, div.af0
- {mso-style-name:������;
+ {mso-style-name:表标题;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
font-size:10.0pt;
font-family:"Arial","sans-serif";}
p.af1, li.af1, div.af1
- {mso-style-name:"��ʽ ��ע + ����";
+ {mso-style-name:"样式 题注 + 居中";
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
@@ -1629,7 +1629,7 @@ p.RightText, li.RightText, div.RightText
font-size:9.0pt;
font-family:"Times New Roman","serif";}
p.af2, li.af2, div.af2
- {mso-style-name:����������;
+ {mso-style-name:表中文字小五;
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
@@ -1637,8 +1637,8 @@ p.af2, li.af2, div.af2
font-size:9.0pt;
font-family:"Times New Roman","serif";}
p.af3, li.af3, div.af3
- {mso-style-name:�ؼ���;
- mso-style-link:"�ؼ��� Char";
+ {mso-style-name:关键词;
+ mso-style-link:"关键词 Char";
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
@@ -1646,12 +1646,12 @@ p.af3, li.af3, div.af3
font-size:10.0pt;
font-family:"Times New Roman","serif";}
span.Char3
- {mso-style-name:"�ؼ��� Char";
- mso-style-link:�ؼ���;
- font-family:����;}
+ {mso-style-name:"关键词 Char";
+ mso-style-link:关键词;
+ font-family:宋体;}
p.af4, li.af4, div.af4
- {mso-style-name:���;
- mso-style-link:"��� Char";
+ {mso-style-name:文件名;
+ mso-style-link:"文件名 Char";
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
@@ -1659,12 +1659,12 @@ p.af4, li.af4, div.af4
font-size:10.0pt;
font-family:"Times New Roman","serif";}
span.Char4
- {mso-style-name:"��� Char";
- mso-style-link:���;
- font-family:����;}
+ {mso-style-name:"文件名 Char";
+ mso-style-link:文件名;
+ font-family:宋体;}
p.af5, li.af5, div.af5
- {mso-style-name:ѡ��;
- mso-style-link:"ѡ�� Char";
+ {mso-style-name:选项;
+ mso-style-link:"选项 Char";
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
@@ -1672,12 +1672,12 @@ p.af5, li.af5, div.af5
font-size:10.0pt;
font-family:"Times New Roman","serif";}
span.Char5
- {mso-style-name:"ѡ�� Char";
- mso-style-link:ѡ��;
- font-family:����;}
+ {mso-style-name:"选项 Char";
+ mso-style-link:选项;
+ font-family:宋体;}
p.af6, li.af6, div.af6
- {mso-style-name:������;
- mso-style-link:"������ Char";
+ {mso-style-name:命令行;
+ mso-style-link:"命令行 Char";
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
@@ -1685,12 +1685,12 @@ p.af6, li.af6, div.af6
font-size:10.0pt;
font-family:"Times New Roman","serif";}
span.Char6
- {mso-style-name:"������ Char";
- mso-style-link:������;
- font-family:����;}
+ {mso-style-name:"命令行 Char";
+ mso-style-link:命令行;
+ font-family:宋体;}
p.af7, li.af7, div.af7
- {mso-style-name:������;
- mso-style-link:"������ Char";
+ {mso-style-name:函数名;
+ mso-style-link:"函数名 Char";
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
@@ -1698,12 +1698,12 @@ p.af7, li.af7, div.af7
font-size:10.0pt;
font-family:"Times New Roman","serif";}
span.Char7
- {mso-style-name:"������ Char";
- mso-style-link:������;
- font-family:����;}
+ {mso-style-name:"函数名 Char";
+ mso-style-link:函数名;
+ font-family:宋体;}
p.af8, li.af8, div.af8
- {mso-style-name:�Ĵ�����;
- mso-style-link:"�Ĵ����� Char";
+ {mso-style-name:寄存器名;
+ mso-style-link:"寄存器名 Char";
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
@@ -1711,12 +1711,12 @@ p.af8, li.af8, div.af8
font-size:10.0pt;
font-family:"Times New Roman","serif";}
span.Char8
- {mso-style-name:"�Ĵ����� Char";
- mso-style-link:�Ĵ�����;
+ {mso-style-name:"寄存器名 Char";
+ mso-style-link:寄存器名;
font-family:"Times New Roman","serif";}
p.af9, li.af9, div.af9
- {mso-style-name:������;
- mso-style-link:"������ Char";
+ {mso-style-name:变量名;
+ mso-style-link:"变量名 Char";
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
@@ -1724,83 +1724,83 @@ p.af9, li.af9, div.af9
font-size:10.0pt;
font-family:"Times New Roman","serif";}
span.Char9
- {mso-style-name:"������ Char";
- mso-style-link:������;
- font-family:����;}
+ {mso-style-name:"变量名 Char";
+ mso-style-link:变量名;
+ font-family:宋体;}
p.58, li.58, div.58
- {mso-style-name:ͼ������С5����;
+ {mso-style-name:图中文字小5号左;
margin:0cm;
margin-bottom:.0001pt;
font-size:9.0pt;
font-family:"Times New Roman","serif";}
p.59, li.59, div.59
- {mso-style-name:ͼ������С5�ſ���;
+ {mso-style-name:图中文字小5号靠左;
margin:0cm;
margin-bottom:.0001pt;
layout-grid-mode:char;
font-size:9.0pt;
font-family:"Times New Roman","serif";}
p.926, li.926, div.926
- {mso-style-name:"��ʽ ������� + ���\: 9\.26 ����";
+ {mso-style-name:"样式 代码程序 + 左侧\: 9\.26 厘米";
margin:0cm;
margin-bottom:.0001pt;
layout-grid-mode:char;
font-size:10.0pt;
- font-family:����;}
+ font-family:宋体;}
span.5Char4
- {mso-style-name:"���� 5 Char";
- mso-style-link:"���� 5";
+ {mso-style-name:"标题 5 Char";
+ mso-style-link:"标题 5";
font-weight:bold;}
span.6Char0
- {mso-style-name:"���� 6 Char";
- mso-style-link:"���� 6";
+ {mso-style-name:"标题 6 Char";
+ mso-style-link:"标题 6";
font-family:"Arial","sans-serif";
font-weight:bold;}
span.7Char
- {mso-style-name:"���� 7 Char";
- mso-style-link:"���� 7";
+ {mso-style-name:"标题 7 Char";
+ mso-style-link:"标题 7";
font-weight:bold;}
span.8Char
- {mso-style-name:"���� 8 Char";
- mso-style-link:"���� 8";
+ {mso-style-name:"标题 8 Char";
+ mso-style-link:"标题 8";
font-family:"Arial","sans-serif";}
span.9Char
- {mso-style-name:"���� 9 Char";
- mso-style-link:"���� 9";
+ {mso-style-name:"标题 9 Char";
+ mso-style-link:"标题 9";
font-family:"Arial","sans-serif";}
span.Chara
- {mso-style-name:"��ע�ı� Char";
- mso-style-link:��ע�ı�;
- font-family:����;}
+ {mso-style-name:"脚注文本 Char";
+ mso-style-link:脚注文本;
+ font-family:宋体;}
span.Charb
- {mso-style-name:"��ע���� Char";
- mso-style-link:��ע����;
- font-family:����;}
+ {mso-style-name:"批注文字 Char";
+ mso-style-link:批注文字;
+ font-family:宋体;}
span.Charc
- {mso-style-name:"ҳü Char";
- mso-style-link:ҳü;
- font-family:����;}
+ {mso-style-name:"页眉 Char";
+ mso-style-link:页眉;
+ font-family:宋体;}
span.Chard
- {mso-style-name:"ҳ�� Char";
- mso-style-link:ҳ��;
- font-family:����;}
+ {mso-style-name:"页脚 Char";
+ mso-style-link:页脚;
+ font-family:宋体;}
span.Chare
- {mso-style-name:"���� Char";
- mso-style-link:����;
- font-family:����;}
+ {mso-style-name:"日期 Char";
+ mso-style-link:日期;
+ font-family:宋体;}
span.HTMLChar
- {mso-style-name:"HTML Ԥ���ʽ Char\,HTML Ԥ�ȸ�ʽ�� Char\,HTML Ԥ�ȸ�ʽ��1 Char\,HTML Ԥ�ȸ�ʽ��2 Char\,HTML Ԥ�ȸ�ʽ��3 Char";
- mso-style-link:"HTML Ԥ���ʽ\,HTML Ԥ�ȸ�ʽ��\,HTML Ԥ�ȸ�ʽ��1\,HTML Ԥ�ȸ�ʽ��2\,HTML Ԥ�ȸ�ʽ��3";
- font-family:����;}
+ {mso-style-name:"HTML 预设格式 Char\,HTML 预先格式化 Char\,HTML 预先格式化1 Char\,HTML 预先格式化2 Char\,HTML 预先格式化3 Char";
+ mso-style-link:"HTML 预设格式\,HTML 预先格式化\,HTML 预先格式化1\,HTML 预先格式化2\,HTML 预先格式化3";
+ font-family:宋体;}
span.Charf
- {mso-style-name:"��ע���� Char";
- mso-style-link:��ע����;
- font-family:����;
+ {mso-style-name:"批注主题 Char";
+ mso-style-link:批注主题;
+ font-family:宋体;
font-weight:bold;}
span.Charf0
- {mso-style-name:"��ע���ı� Char";
- mso-style-link:��ע���ı�;
- font-family:����;}
+ {mso-style-name:"批注框文本 Char";
+ mso-style-link:批注框文本;
+ font-family:宋体;}
.MsoChpDefault
{font-size:10.0pt;}
/* Page Definitions */
@@ -1824,7 +1824,7 @@ ul
����程序12-7 linux/fs/file_table.c 6 7
-#include <linux/fs.h> // �ļ�ϵͳͷ�ļ��������ļ����ṹ��file,buffer_head,m_inode�ȣ��� 8 9
struct file file_table[NR_FILE]; // �ļ�������(64��)�� 10 ����程序12-8 linux/fs/block_dev.c 6 7
-#include <errno.h> // �����ͷ�ļ�������ϵͳ�и��ֳ����š� 8 9
-#include <linux/sched.h> // ���ȳ���ͷ�ļ�������������ṹtask_struct������0�����ݣ�
- // ����һЩ�й��������������úͻ�ȡ��Ƕ��ʽ��ຯ������䡣 10
-#include <linux/kernel.h> // �ں�ͷ�ļ�������һЩ�ں˳��ú�����ԭ�ζ��塣 11
-#include <asm/segment.h> // �β���ͷ�ļ����������йضμĴ���������Ƕ��ʽ��ຯ���� 12
-#include <asm/system.h> // ϵͳͷ�ļ������������û���������/�ж��ŵȵ�Ƕ��ʽ���ꡣ 13 // �豸���ݿ�����ָ�����顣ÿ��ָ����ָ��ָ�����豸�ŵ��ܿ�������hd_sizes[]������ // 设备数据块总数指针数组。每个指针项指向指定主设备号的总块数数组hd_sizes[]。该总 // ��������ÿһ���Ӧ���豸��ȷ����һ�����豸����ӵ�е����ݿ�������1���С = 1KB���� // 块数数组每一项对应子设备号确定的一个子设备上所拥有的数据块总数(1块大小 = 1KB)。 14
extern int *blk_size[];
-// blk_drv/ll_rw_blk.c��49�С� 15 //// ���ݿ�д���� - ��ָ���豸�Ӹ���ƫ�ƴ�д��ָ���������ݡ� //// 数据块写函数 - 向指定设备从给定偏移处写入指定长度数据。 // ������dev
-- �豸�ţ�pos - �豸�ļ���ƫ����ָ�룻buf - �û��ռ��л�������ַ�� // 参数:dev
+- 设备号;pos - 设备文件中偏移量指针;buf - 用户空间中缓冲区地址; // count - Ҫ���͵��ֽ����� // count - 要传送的字节数。 // ������д���ֽ�������û��д���κ��ֽڻ�������س����š� // 返回已写入字节数。若没有写入任何字节或出错,则返回出错号。 // �����ں���˵��д����������ٻ�������д�����ݡ�ʲôʱ����������д���豸���ɸ��ٻ� // 对于内核来说,写操作是向高速缓冲区中写入数据。什么时候数据最终写入设备是由高速缓 // �������������������ġ����⣬��Ϊ���豸���Կ�Ϊ��λ���ж�д����˶���д��ʼλ�� // 冲管理程序决定并处理的。另外,因为块设备是以块为单位进行读写,因此对于写开始位置 // �����ڿ���ʼ��ʱ����Ҫ�Ƚ���ʼ�ֽ����ڵ������������Ȼ����Ҫд�����ݴ�д��ʼ�� // 不处于块起始处时,需要先将开始字节所在的整个块读出,然后将需要写的数据从写开始处 // ��д���ÿ飬�ٽ�������һ������д�̣������ɸ��ٻ������ȥ�������� // 填写满该块,再将完整的一块数据写盘(即交由高速缓冲程序去处理)。 16 int
block_write(int dev, long * count) 17 { // �������ļ���λ��pos����ɿ�ʼ��д�̿�Ŀ����block���������д��1�ֽ��ڸÿ��� // 首先由文件中位置pos换算成开始读写盘块的块序号block,并求出需写第1字节在该块中 // ��ƫ��λ��offset�� // 的偏移位置offset。 18
int block = *pos >> BLOCK_SIZE_BITS;
-// pos�����ļ����ݿ�š� 19
int offset = *pos & (BLOCK_SIZE-1);
-// pos�����ݿ���ƫ��ֵ�� 20
int chars; 24
register char * p;
- // �ֲ��Ĵ���������������ڼĴ����С� 25 // ��дһ�����豸�ļ�ʱ��Ҫ��д�������ݿ�����Ȼ���ܳ���ָ���豸��������������ݿ��� // 在写一个块设备文件时,要求写的总数据块数当然不能超过指定设备上容许的最大数据块总 // ���������������ȡ��ָ���豸�Ŀ�����size���ȽϺ����ƺ�������������д�����ݳ��ȡ� // 数。因此这里首先取出指定设备的块总数size来比较和限制函数参数给定的写入数据长度。 // ���ϵͳ��û�ж��豸ָ�����ȣ���ʹ��Ĭ�ϳ���0x7fffffff��2GB���飩�� // 如果系统中没有对设备指定长度,就使用默认长度0x7fffffff(2GB个块)。 26
if (blk_size[MAJOR(dev)]) 29
size = 0x7fffffff; // Ȼ�����Ҫд����ֽ���count��ѭ��ִ�����²�����ֱ������ȫ��д�롣��ѭ��ִ�й��� // 然后针对要写入的字节数count,循环执行以下操作,直到数据全部写入。在循环执行过程 // �У�����ǰд�����ݵĿ���Ѿ����ڻ����ָ���豸���ܿ���������д�ֽ������˳��� // 中,若当前写入数据的块号已经大于或等于指定设备的总块数,则返回已写字节数并退出。 // Ȼ���ټ����ڵ�ǰ���������ݿ��п�д����ֽ����������Ҫд����ֽ������һ�飬�� // 然后再计算在当前处理的数据块中可写入的字节数。如果需要写入的字节数填不满一块,那 // ô��ֻ��дcount�ֽڡ��������Ҫд1���������ݣ���ֱ������1����ٻ���飬������ // 么就只需写count字节。如果正好要写1块数据内容,则直接申请1块高速缓冲块,并把用 // �����ݷ��뼴�ɡ��������Ҫ���뽫��д�벿�����ݵ����ݿ飬��Ԥ�����������ݡ�Ȼ�� // 户数据放入即可。否则就需要读入将被写入部分数据的数据块,并预读下两块数据。然后将 // ��ŵ���
-1��Ϊ�´β����������������������ʧ�ܣ�����д�ֽ��������û��д // 块号递增
+1,为下次操作做好准备。如果缓冲块操作失败,则返回已写字节数,如果没有写 // ���κ��ֽڣ��س����ţ��������� // 入任何字节,则返回出错号(负数)。 30
while (count>0) { 33
chars = BLOCK_SIZE - offset;
-// �����д����ֽ����� 34
if (chars > count) 37
bh = getblk(dev,block);
-// buffer.c ��206��322�� 38
else 42
return written?written:-EIO; // �����Ȱ�ָ��pָ��������ݵĻ�����п�ʼд�����ݵ�λ�ô��������һ��ѭ��д����� // 接着先把指针p指向读出数据的缓冲块中开始写入数据的位置处。若最后一次循环写入的数 // �ݲ���һ�飬����ӿ鿪ʼ����д���ģ�������ֽڣ����������Ԥ������offsetΪ�㡣 // 据不足一块,则需从块开始处填写(修改)所需的字节,因此这里需预先设置offset为零。 // �˺��ļ���ƫ��ָ��posǰ�ƴ˴ν�Ҫд���ֽ���chars�����ۼ���ЩҪд���ֽ�����ͳ // 此后将文件中偏移指针pos前移此次将要写的字节数chars,并累加这些要写的字节数到统 // ��ֵwritten�С��ٰѻ���Ҫд�ļ���ֵcount ��ȥ�˴�Ҫд���ֽ���chars��Ȼ�����Ǵ� // 计值written中。再把还需要写的计数值count 减去此次要写的字节数chars。然后我们从 // �û�����������chars���ֽڵ�pָ��ĸ��ٻ�����п�ʼд���λ�ô��������������� // 用户缓冲区复制chars个字节到p指向的高速缓冲块中开始写入的位置处。复制完后就设置 // �û����������ı�־�����ͷŸû�������Ҳ���û��������ü����ݼ�1���� // 该缓冲区块已修改标志,并释放该缓冲区(也即该缓冲区引用计数递减1)。 43
p = offset + bh->b_data; 46
written += chars;
-// �ۼ�д���ֽ����� 47
count -= chars; 53
return written;
-// ������д����ֽ����������˳��� 54 } 55 //// ���ݿ������ - ��ָ���豸��λ�ô�����ָ���������ݵ��û��������С� //// 数据块读函数 - 从指定设备和位置处读入指定长度数据到用户缓冲区中。 // ������dev
-- �豸�ţ�pos - �豸�ļ���ƫ����ָ�룻buf - �û��ռ��л�������ַ�� // 参数:dev
+- 设备号;pos - 设备文件中偏移量指针;buf - 用户空间中缓冲区地址; // count - Ҫ���͵��ֽ����� // count - 要传送的字节数。 // �����Ѷ����ֽ�������û�ж����κ��ֽڻ�������س����š� // 返回已读入字节数。若没有读入任何字节或出错,则返回出错号。 56 int
block_read(int dev, unsigned long * buffer_head * bh; 64
register char * p; //
-�ֲ��Ĵ���������������ڼĴ����С� 65 // �ڶ�һ�����豸�ļ�ʱ��Ҫ����������ݿ�����Ȼ���ܳ���ָ���豸��������������ݿ��� // 在读一个块设备文件时,要求读的总数据块数当然不能超过指定设备上容许的最大数据块总 // ���������������ȡ��ָ���豸�Ŀ�����size���ȽϺ����ƺ������������Ķ������ݳ��ȡ� // 数。因此这里首先取出指定设备的块总数size来比较和限制函数参数给定的读入数据长度。 // ���ϵͳ��û�ж��豸ָ�����ȣ���ʹ��Ĭ�ϳ���0x7fffffff��2GB���飩�� // 如果系统中没有对设备指定长度,就使用默认长度0x7fffffff(2GB个块)。 66
if (blk_size[MAJOR(dev)]) 69
size = 0x7fffffff; // Ȼ�����Ҫ������ֽ���count��ѭ��ִ�����²�����ֱ������ȫ�����롣��ѭ��ִ�й��� // 然后针对要读入的字节数count,循环执行以下操作,直到数据全部读入。在循环执行过程 // �У�����ǰ�������ݵĿ���Ѿ����ڻ����ָ���豸���ܿ��������Ѷ��ֽ������˳��� // 中,若当前读入数据的块号已经大于或等于指定设备的总块数,则返回已读字节数并退出。 // Ȼ���ټ����ڵ�ǰ���������ݿ����������ֽ����������Ҫ������ֽ���������һ�飬�� // 然后再计算在当前处理的数据块中需读入的字节数。如果需要读入的字节数还不满一块,那 // ô��ֻ���count�ֽڡ�Ȼ����ö��麯��breada()������Ҫ�����ݿ飬��Ԥ�����������ݣ� // 么就只需读count字节。然后调用读块函数breada()读入需要的数据块,并预读下两块数据, // ������������������Ѷ��ֽ��������û�ж����κ��ֽڣ��س����š�Ȼ��� // 如果读操作出错,则返回已读字节数,如果没有读入任何字节,则返回出错号。然后将块号 // ����1��Ϊ�´β����������������������ʧ�ܣ�����д�ֽ��������û�ж����� // 递增1。为下次操作做好准备。如果缓冲块操作失败,则返回已写字节数,如果没有读入任 // ���ֽڣ��س����ţ��������� // 何字节,则返回出错号(负数)。 70
while (count>0) { 78
block++; // �����Ȱ�ָ��pָ������̿�Ļ�����п�ʼ�������ݵ�λ�ô��������һ��ѭ���������� // 接着先把指针p指向读出盘块的缓冲块中开始读入数据的位置处。若最后一次循环读操作的 // ���ݲ���һ�飬����ӿ���ʼ����ȡ�����ֽڣ����������Ԥ������offsetΪ�㡣 �˺� // 数据不足一块,则需从块起始处读取所需字节,因此这里需预先设置offset为零。 此后将 // �ļ���ƫ��ָ��posǰ�ƴ˴ν�Ҫ�����ֽ���chars�������ۼ���ЩҪ�����ֽ�����ͳ��ֵ // 文件中偏移指针pos前移此次将要读的字节数chars,并且累加这些要读的字节数到统计值 // read�С��ٰѻ���Ҫ���ļ���ֵcount��ȥ�˴�Ҫ�����ֽ���chars��Ȼ�����ǴӸ��ٻ��� // read中。再把还需要读的计数值count减去此次要读的字节数chars。然后我们从高速缓冲 // ����pָ��Ŀ�ʼ����λ�ô�����chars���ֽڵ��û��������У�ͬʱ���û�������ָ��ǰ // 块中p指向的开始读的位置处复制chars个字节到用户缓冲区中,同时把用户缓冲区指针前 // �ơ����θ��������ͷŸû���顣 // 移。本次复制完后就释放该缓冲块。 79
p = offset + bh->b_data; 82
read
+= chars;
-// �ۼƶ����ֽ����� 83
count -= chars; 88
return read; //
-�����Ѷ�ȡ���ֽ����������˳��� 89 } ����程序12-9 linux/fs/file_dev.c 6 7
-#include <errno.h> // �����ͷ�ļ�������ϵͳ�и��ֳ����š� 8
-#include <fcntl.h> // �ļ�����ͷ�ļ��������ļ������������IJ������Ƴ������ŵĶ��塣 9 10
-#include <linux/sched.h> // ���ȳ���ͷ�ļ�������������ṹtask_struct������0�����ݵȡ� 11
-#include <linux/kernel.h> // �ں�ͷ�ļ�������һЩ�ں˳��ú�����ԭ�ζ��塣 12
-#include <asm/segment.h> // �β���ͷ�ļ����������йضμĴ���������Ƕ��ʽ��ຯ���� 13 14
#define MIN(a,b) (((a)<(b))?(a):(b))
-// ȡa,b�е���Сֵ�� 15
#define MAX(a,b) (((a)>(b))?(a):(b))
-// ȡa,b�е����ֵ�� 16 //// �ļ������� - ����i�ڵ���ļ��ṹ����ȡ�ļ������ݡ� //// 文件读函数 - 根据i节点和文件结构,读取文件中数据。 // ��i�ڵ����ǿ���֪���豸�ţ���filp�ṹ����֪���ļ��е�ǰ��дָ��λ�á�bufָ���� // 由i节点我们可以知道设备号,由filp结构可以知道文件中当前读写指针位置。buf指定用 // ���ռ��л�������λ�ã�count����Ҫ��ȡ���ֽ����� ����ֵ��ʵ�ʶ�ȡ���ֽ���������� // 户空间中缓冲区的位置,count是需要读取的字节数。 返回值是实际读取的字节数,或出错 // �ţ�С��0���� // 号(小于0)。 17 int
file_read(struct buffer_head * bh; 21 // �����жϲ�������Ч�ԡ�����Ҫ��ȡ���ֽڼ���countС�ڵ����㣬��0��������Ҫ�� // 首先判断参数的有效性。若需要读取的字节计数count小于等于零,则返回0。若还需要读 // ȡ���ֽ���������0����ѭ��ִ�����������ֱ������ȫ���������������⡣�ڶ�ѭ������ // 取的字节数不等于0,就循环执行下面操作,直到数据全部读出或遇到问题。在读循环操作 // �����У����Ǹ���i�ڵ���ļ����ṹ��Ϣ�������� bmap() �õ������ļ���ǰ��дλ�õ� // 过程中,我们根据i节点和文件表结构信息,并利用 bmap() 得到包含文件当前读写位置的 // ���ݿ����豸�϶�Ӧ�������nr����nr��Ϊ0�����i�ڵ�ָ�����豸�϶�ȡ�����顣 // 数据块在设备上对应的逻辑块号nr。若nr不为0,则从i节点指定的设备上读取该逻辑块。 // ���������ʧ�����˳�ѭ������nrΪ0����ʾָ�������ݿ鲻���ڣ��û����ָ��ΪNULL�� // 如果读操作失败则退出循环。若nr为0,表示指定的数据块不存在,置缓冲块指针为NULL。 // (filp->f_pos)/BLOCK_SIZE ���ڼ�����ļ���ǰָ���������ݿ�š� // (filp->f_pos)/BLOCK_SIZE 用于计算出文件当前指针所在数据块号。 22
if ((left=count)<=0) 25
if (nr = bmap(inode,(filp->f_pos)/BLOCK_SIZE)) { // inode.c��140�� 26
if (!(bh=bread(inode->i_dev,nr))) 29
bh = NULL; // �������Ǽ����ļ���дָ�������ݿ��е�ƫ��ֵnr�����ڸ����ݿ�������ϣ����ȡ���ֽ��� // 接着我们计算文件读写指针在数据块中的偏移值nr,则在该数据块中我们希望读取的字节数 // Ϊ (BLOCK_SIZE
-- nr)��Ȼ������ڻ����ȡ���ֽ���left���Ƚϣ�����Сֵ��Ϊ���β��� // 为 (BLOCK_SIZE
+- nr)。然后和现在还需读取的字节数left作比较,其中小值即为本次操作 // ���ȡ���ֽ���chars����� (BLOCK_SIZE - nr) > left����˵���ÿ�����Ҫ��ȡ�����һ // 需读取的字节数chars。如果 (BLOCK_SIZE - nr) > left,则说明该块是需要读取的最后一 // �����ݣ���֮����Ҫ��ȡ��һ�����ݡ�֮�������д�ļ�ָ�롣
-ָ��ǰ�ƴ˴ν���ȡ���� // 块数据,反之则还需要读取下一块数据。之后调整读写文件指针。
+指针前移此次将读取的字 // ����chars��ʣ���ֽڼ���left��Ӧ��ȥchars�� // 节数chars。剩余字节计数left相应减去chars。 30
nr = filp->f_pos % BLOCK_SIZE; 33
left -= chars; // ��������豸�϶��������ݣ���pָ����п�ʼ��ȡ���ݵ�λ�ã����Ҹ���chars�ֽ� // 若上面从设备上读到了数据,则将p指向缓冲块中开始读取数据的位置,并且复制chars字节 // ���û�������buf�С��������û�������������chars��0ֵ�ֽڡ� // 到用户缓冲区buf中。否则往用户缓冲区中填入chars个0值字节。 34
if (bh) { 43
} // �ĸ�i�ڵ�ķ���ʱ��Ϊ��ǰʱ�䡣���ض�ȡ���ֽ���������ȡ�ֽ���Ϊ0���س����š� // 修改该i节点的访问时间为当前时间。返回读取的字节数,若读取字节数为0,则返回出错号。 // CURRENT_TIME�Ƕ�����include/linux/sched.h��142���ϵĺ꣬���ڼ���UNIXʱ�䡣���� // CURRENT_TIME是定义在include/linux/sched.h第142行上的宏,用于计算UNIX时间。即从 // 1970��1��1��0ʱ0�뿪ʼ������ǰ��ʱ�䡣��λ���롣 44
inode->i_atime = CURRENT_TIME; //// �ļ�д���� - ����i�ڵ���ļ��ṹ��Ϣ�����û�����д���ļ��С� //// 文件写函数 - 根据i节点和文件结构信息,将用户数据写入文件中。 // ��i�ڵ����ǿ���֪���豸�ţ�����file�ṹ����֪���ļ��е�ǰ��дָ��λ�á�bufָ�� // 由i节点我们可以知道设备号,而由file结构可以知道文件中当前读写指针位置。buf指定 // �û�̬�л�������λ�ã�countΪ��Ҫд����ֽ����� ����ֵ��ʵ��д����ֽ���������� // 用户态中缓冲区的位置,count为需要写入的字节数。 返回值是实际写入的字节数,或出错 // �ţ�С��0���� // 号(小于0)。 48 int
file_write(struct /* * ok�����������ͬʱдʱ��append�������ܲ��У����������������������������� * ok,当许多进程同时写时,append操作可能不行,但那又怎样。不管怎样那样做会 * ���»���һ�š� * 导致混乱一团。 */ // ����ȷ������д���ļ���λ�á������Ҫ���ļ����������ݣ����ļ���дָ���Ƶ��ļ�β // 首先确定数据写入文件的位置。如果是要向文件后添加数据,则将文件读写指针移到文件尾 // ��������ͽ����ļ���ǰ��дָ�봦д�롣 // 部。否则就将在文件当前读写指针处写入。 60
if (filp->f_flags & O_APPEND) 63
pos = filp->f_pos; // Ȼ������д���ֽ���i���տ�ʼʱΪ0��С��ָ��д���ֽ���countʱ��ѭ��ִ�����²����� // 然后在已写入字节数i(刚开始时为0)小于指定写入字节数count时,循环执行以下操作。 // ��ѭ�����������У�������ȡ�ļ����ݿ�� ( pos/BLOCK_SIZE ) ���豸�϶�Ӧ������� // 在循环操作过程中,我们先取文件数据块号 ( pos/BLOCK_SIZE ) 在设备上对应的逻辑块号 // block�������Ӧ�����鲻���ھʹ���һ�顣����õ�������� = 0�����ʾ����ʧ�ܣ� // block。如果对应的逻辑块不存在就创建一块。如果得到的逻辑块号 = 0,则表示创建失败, // �����˳�ѭ�����������Ǹ��ݸ�����Ŷ�ȡ�豸�ϵ���Ӧ���飬������Ҳ�˳�ѭ���� // 于是退出循环。否则我们根据该逻辑块号读取设备上的相应逻辑块,若出错也退出循环。 64
while (i<count) { 68
break; // ��ʱ�����ָ��bh��ָ��ն�����ļ����ݿ顣����������ļ���ǰ��дָ���ڸ����ݿ��� // 此时缓冲块指针bh正指向刚读入的文件数据块。现在再求出文件当前读写指针在该数据块中 // ��ƫ��ֵc������ָ��pָ����п�ʼд�����ݵ�λ�ã����øû�������ı�־������ // 的偏移值c,并将指针p指向缓冲块中开始写入数据的位置,并置该缓冲块已修改标志。对于 // ���е�ǰָ�룬�ӿ�ʼ��дλ�õ���ĩ����д��c =(BLOCK_SIZE - c)���ֽڡ���c����ʣ�� // 块中当前指针,从开始读写位置到块末共可写入c =(BLOCK_SIZE - c)个字节。若c大于剩余 // ����д����ֽ��� (count - i)����˴�ֻ����д��c = (count - i)���ֽڼ��ɡ� // 还需写入的字节数 (count - i),则此次只需再写入c = (count - i)个字节即可。 69
@@ -2167,19 +2167,19 @@ bh->b_dirt = 1; // ��д������֮ǰ��������Ԥ�����ú���һ��ѭ������Ҫ��д�ļ��е�λ�á�������ǰ� // 在写入数据之前,我们先预先设置好下一次循环操作要读写文件中的位置。因此我们把pos // ָ��ǰ�ƴ˴���д����ֽ����������ʱposλ��ֵ�������ļ���ǰ���ȣ�����i�ڵ��� // 指针前移此次需写入的字节数。如果此时pos位置值超过了文件当前长度,则修改i节点中 // �ļ������ֶΣ�����i�ڵ����ı�־��Ȼ��Ѵ˴�Ҫд����ֽ���c�ۼӵ���д���ֽڼ� // 文件长度字段,并置i节点已修改标志。然后把此次要写入的字节数c累加到已写入字节计 // ��ֵi�У���ѭ���ж�ʹ�á����Ŵ��û�������buf�и���c���ֽڵ����ٻ������pָ�� // 数值i中,供循环判断使用。接着从用户缓冲区buf中复制c个字节到高速缓冲块中p指向 // �Ŀ�ʼλ�ô������������ͷŸû���顣 // 的开始位置处。复制完后就释放该缓冲块。 74
pos += c; 83
} // �������Ѿ�ȫ��д���ļ�������д���������з�������ʱ�ͻ��˳�ѭ������ʱ���Ǹ����ļ� // 当数据已经全部写入文件或者在写操作过程中发生问题时就会退出循环。此时我们更改文件 // ��ʱ��Ϊ��ǰʱ�䣬�������ļ���дָ�롣����˴β����������ļ�β�������ݣ������ // 修改时间为当前时间,并调整文件读写指针。如果此次操作不是在文件尾添加数据,则把文 // ����дָ���������ǰ��дλ��pos�����������ļ�i�ڵ����ʱ��Ϊ��ǰʱ�䡣��� // 件读写指针调整到当前读写位置pos处,并更改文件i节点的修改时间为当前时间。最后返 // ��д����ֽ�������д���ֽ���Ϊ0���س�����-1�� // 回写入的字节数,若写入字节数为0,则返回出错号-1。 84
inode->i_mtime = CURRENT_TIME;