لینوکس را بیشتر بشناسیم (پارت4)VFS

یکی از اساسی ترین نیازی هایی که یه سیستم عامل امروزی باید بر طرفش کنه ، مدیریت فایل هاس . فایل ها به طریقی که ما باهاشون کار می کنیم روی دیوایس های ذخیره سازی نوشته یا خونده نمی شن . خب پس ما به چیزی احتیاج داریم که این عملیات نوشتن و خوندن روی دیوایس ها رو مدیریت کنه . زدم فلان فایل باز شه با اطلاعات اضافی که در مورد فایل داره دستور خوندنشو صادر کنه و نشونمون بده . همه اینکارارو فایل سیستم ها انجام میدن ولی لینوکس یه لایه abstract پیاده سازی کرده که کارا راحت تر جلو بره .

What is VFS?

در واقع بخشی هست که سیستم کال های مربوط به فایل و فایل سیستم رو هندل می کنه تو قسمت دو با سیستم کال ها آشنا شدیم . VFS یه واسط جنریک ( کلی) بین یوزر و فایل سیستم های مختلفه . این نوع پیاده سازی انتزاعی ، نوشتن و پیاده سازی فایل سیستم های مختلف رو راحت تر می کنه . یعنی برای اینکه فایل سیستم بنویسیم فقط کافیه که از API هایی که VFS ارائه می ده استفاده کنیم . و مسائل کلی خوندن و نوشتن و ورودی /خروجی به عهده VFS خواهد بود . اگه بخواییم یه دسته بندی کلی در مورد فایل سیستم ها داشته باشیم به صورت زیر خواهد بود :

  • disk file systems ( ext3 , ext4 , fat , ntfs )
  • network file systems (nfs , smbfs/cifs , ncp)
  • virtual file system(procfs , sysfs , sockfs pipefs)

vfs abstract layer

در واقع ایده پشت VFS این بوده که یه مدل برای فایل بسازن که بتونه فایل ها رو در فایل سیستم های مختلف نمایش بده . پس تنها کاری که فایل سیستم ها باید انجام بدن اینکه با vfs ارتباط بر قرار کنن . این مسئله باعث میشه که نوشتن فایل سیستم های جدید بسیار آسون بشه . برا همینه که لینوکس از کلی فایل سیستم پشتیبانی می کنه یه شرکت می تونه یک نوع جدید از فایل سیستم رو بنویسه و کافیه روی vfs سوار شه و حله و هیچ مشکلی نیست .

لینوکس از vfs برای درست کردن یه درخت از فایل ها و دایرکتوری ها استفاده می کنه و فایل سیستم های جدید به عنوان یه زیر شاخه از این درخت اضافه میشه که به این عملیات mount میگن . حتی این امکان وجود داره که از یه فایل ساده به عنوان virtual block device استفاده کنیم در واقع یه فایله ولی به عنوان یه دیوایس ذخیره سازی mount میشه .

مدل کلی فایل سیستم

گفتیم که هر نوع پیاده سازی فایل سیستم در آخر تبدیل به یه مدل واحد از فایل سیستم که تو vfs هست می شه که یه سری موجودیت های تعریف شده داره : superbloc , inode , dentry این موجودیت ها متادیتا هستن اطلاعاتی در مورد اطلاعات و داد ها رو نگه میدارن .

dentry

vfs همه چی رو به چشم فایل می بینه حتی دایرکتوری ها رو مثلا این مسیرو در نظر بگیرید bin/vi/ تو این مسیر bin فایل مخصوصی به اسم دایرکتوری هست و vi یه فایل عادی . این وحدت و یگانگی می تونه مفید باشه ولی vfs به چیزی احتیاج داره که بتونه اینارو سریع تشخیص بده بدون اینکه نیاز باشه کل مسیرو دونه به دونه پارس کنه کدوم فایل و کدوم دایرکتوری هست .پس ساختاری داده ای درست کردن که بهش میگن directory entry یا به اختصار dentry به فارسی میشه ورودی دایرکتوری( ! ) . مثلا دوباره این مسیرو در نظر بگیرید bin/vi/ تو این مثال سه تا شیء dentry داریم : / , bin , vi . دوتای اولی دایرکتوری هست و آخری فایل . پس همه اجزا که تو یه مسیر می بنید من جمله فایل ها dentry هستن . پارس کردن یه مسیر و حرکت کردن به صورت جز به جز و تشخیص اینکه فایله یا دایرکتوری کار وقت گیری هست . dentry این فرآیند رو آسون و سریع می کنه . به صورت کلی ساختار dentry شامل دوتا فیلد هست :

  1. آی نود
  2. رشته ای که نشون دهنده اسمش هست

پس هدف dentry فقط اینکه به سرعت فایل عادی یا دایرکتوری بودن رو مشخص کنه

inode

آی نود همه اطلاعاتی که کرنل برای دستکاری فایل ها دایرکتوری ها نیاز داره رو در اختیار کرنل میزاره . در واقع هر آی نود نشان دهنده یک فایل در فایل سیستم هست . آی نود اطلاعات زیرو نگه میداره :‌

  • نوع فایل ( فایل عادی ، دایرکتوری ، فایل های خاص مثل پایپ ها ، بلاک دیوایس ها و غیره )
  • سایز فایل
  • دسترسی ها
  • زمان ادیت و دسترسی به فایل
  • مکان فایل روی دیسک ( اشاره گری به بلاکی از دیسک که شامل داده ها )

فایل سیستم های که بدون آی نود هستن در واقع متادیتا رو به عنوان قسمتی از فایل نگه میدارن یا حتی بعضیا یه دیتابیس برای اینکا در نظر میگیرن . در هر صورت آی نود توی vfs هست تا اطلاعات فایل هارو نگه داره . می تونید با آپشن -i تو دستور ls آی نودهای فایلاتونو ببینید ls -i

superblocks

سوپربلاک های هم به صورت موجودیت های فیزیکی روی دیسک هستن و هم تو vfs . سوپربلاک ها متادیتاهایی نگه میداره که برای کارکرد اون فایل سیستم مورد نیازه این اطلاعات برای مدیریت فایل سیستم های mount شده لازمه . سوپربلاک ها رو دیسک های فیزیکی دخیره میشن ولی فایل سیستم هایی که دیسک بیس نیستن این سوپر بلاک رو تولید و فقط در حافظه نگه میدارن مثل (sysfs) . سوپر بلاک برای هر فایل سیستم اطلاعات زیر رو نگه میداره :

  • دیوایس فیزیکی که سوپربلاک ( یا اون فایل سیستمی که این سوپر بلاک در مورد اون هست) روش مقیم شده
  • اندازه بلاک
  • حداکثر اندازه فایل
  • نوع فایل سیستم (ntfs , ext4 or etc)
  • عملیاتی که ساپورت می کنه
  • عدد مخصوص (شناسه فایل سیستم)
  • dentry دایرکتوری روت

file

فایل به سطح کاربر خیلی نزدیکه . و ساختار فایل فقط به عنوان موجودیتی تو vfs هست و روی دیسک هیچ معادلی نداره . آی نود ساختار انتزاعی از فایل رو دیسک هست و ساختار فایل انتزاعی از یک فایل باز هست . ساختار فایل شامل اطلاعات زیره :‌

  • محل مکان نمای فایل
  • مجوز های باز کردن فایل
  • اشاره گری به آی نود

inode cache and dentry cache

لایه vfs کلی زحمت میکشه و اجزای یک مسیرو تبدیل به آبجکت های dentry می کنه منطقی اینه که یه جایی اینارو ذخیره کنه که اگه دوباره نیاز شد تا مسیر های تکراری رو هندل کنه از اون آبجکت های کش شده استفاده کنه . که بهش dentry cache یا به اختصار dcache میگن . این کش سه قسمت داره :

  1. لیستی از dentry های استفاده شده
  2. لیست لینک شده از dentry هایی که اخیرا کم استفاده شدن . اضافه شدن به این لیست به ترتیب زمان هست پس جدیدتر ها به head نزدیک ترن . و هنگامی که میخواد حذف بشه از ته این لیست که قدیمی تر هست حذف می شه .
  3. یه هش تیبل و تابع محاسبه هش برای اینکه سریعا dentry مختص به مسیر رو پیدا کنه

از کش برای آی نود ها هم استفاده می شه . این کار با دوتا لیست انجام میشه یکیش آی نودهایی هست که در حال حاضر استفاده میشه . و اونیکی آی نود های استفاده نشده . آی نودهایی که استفاده شده ان توی هش تیبل ذخیره میشن . تو پیاده سازی که انجام شده dcache کنترل کننده کش آی نودهاست اگه شی dentry وجود داشته پس آبجکت آی نودش هم توی کش هست . عملیات لوک آپ روی dcache انجام میشه و نتیجه یه آبجکت آی نود خواهد بود .

حالا که تا اینجا اومدیم بهتره با ابزار ساخت فایل سیستم ، دستکاری و عملیات mounting هم آشنا بشیم .

ساخت فایل سیستم روی بلاک دیوایس

اول از همه باید لیست بلاک دیوایس هامو ببینیم . این اطلاعات تو دایرکتوری مشهور /dev هست . در واقع هر قطعه سخت افزاری که به یه سیستم لینوکسی متصل میکنید یک فایل براش ایجاد میشه این فایل عادی نیست و با اسم بلاک دیوایس شناخته میشن . دستور ls -l /dev

lrwxrwxrwx  1 root root             4 Dec 12 18:57 rtc -> rtc0
crw-------  1 root root      249,   0 Dec 12 18:57 rtc0
brw-rw----  1 root disk        8,   0 Dec 12 18:57 sda
brw-rw----  1 root disk        8,   1 Dec 12 18:57 sda1
brw-rw----  1 root disk        8,   2 Dec 12 18:57 sda2
brw-rw---- 1  root disk 	   8, 32 Dec 12 20:23  sdc
brw-rw---- 1  root disk        8, 33 Dec 12 20:26  sdc1

یه همچین خروجی خواهیم داشت خطوطی که با کاراکتر b شروع میشن بلاک دیوایس تلقی میشن . مثلا sda به عنوان هارد دیسک اول هست و sdb هارد دیسک دوم و اعدادی که جلوش نوشته میشه مثل sda1 نشون دهنده دارتیشنی هست روی هارد دیسک اول . خب من اینجا یه فلش به سیستم زدم که اسم بلاک دیوایسش sdc هست . یه پارتیشن ntfs داره روش و من میخوام فایل سیستمشو عوض کنم به ext2 . دقت کنید تمامی فایلاتون از دست خواهد رفت !

یه نکته ای که باید مدنظر داشته باشید اینکه هیچ وقت ایجاد فایل سیستم یا در ادامه که فایل سیستم ها به اصطلاح tune می کنیم نباید اون فایل سیستم mount شده باشه . پس بهتره تا آخر این پستو برید و بعد اقدام به ساختن فایل سیستم بکنید .

من این دستورو وارد می کنیم و یه فایل سیستم ext2 می سازم . ابزاری که استفاده می کنیم mkfs هست . همونطور که در خروجی مشخص هست از من سوال کرد که فایل سیستم فعلی ntfs هست میخوای ادامه بدی که من y زدم . شروع میکنه به ساختن جدول آی نودها ، سوپربلاک رو تولید می کنه و تمام .

sudo mkfs -t ext2 /dev/sdc1 
 
mke2fs 1.45.5 (07-Jan-2020)
/dev/sdc1 contains a ntfs file system labelled 'Amin'
Proceed anyway? (y,N) y
Creating filesystem with 1975296 4k blocks and 493856 inodes
Filesystem UUID: 070f4c1c-1acd-428b-9b54-9c27882004fa
Superblock backups stored on blocks: 
	32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632

Allocating group tables: done                            
Writing inode tables: done                            
Writing superblocks and filesystem accounting information: done 

برامون ۱۹۷۵۲۹۶ تا بلاک ۴ کیلوبایتی ساخت و ۴۹۳۸۵۶ تا آی نود که حداکثر فایل و دایرکتوری هست که می تونیم رو این فایل سیستم بسازیم . اطلاعات خیلی بیشتر از این رو می تونیم با ابزار dumpe2fs به دست بیاریم من این دستورو برای این فایل سیستم اجرا کردم و خروجی خیلی مفصلی بهم داد ولی فقط به قسمت های مهمش اشاره می کنم .

sudo dumpe2fs /dev/sdc1 -h
Filesystem UUID:          070f4c1c-1acd-428b-9b54-9c27882004fa
Filesystem magic number:  0xEF53
...
Filesystem state:         clean
Errors behavior:          Continue
Filesystem OS type:       Linux
Inode count:              493856
Block count:              1975296
Reserved block count:     98764
Free blocks:              1939946
Free inodes:              493845
First block:              0
Block size:               4096
Fragment size:            4096
....
Filesystem created:       Sat Dec 12 20:25:16 2020
....
Mount count:              1
Maximum mount count:      -1
Last checked:             Sat Dec 12 20:25:16 2020
....
First inode:              11
Inode size:	          256
....

تو خروجی بالا قسمتی های مهمی هست که چنتاشو توضیح میدم . قسمتی هست به اسم Reserved block count .همونطور که از اسمش پیداس فضای رزرو شده هست . اگه دیسکمون پر بشه و به فضای رزرو شده برسه لینوکس بهمون هشدار میده که دیسک پر شده در حالی که کاملا پر نشده و فضای رزرو شده هنوز آزاده . این مقدارو میشه تغییر داد که به صورت دیفالت ۵ درصده . به صورت دیفالت کاربر روت می تونه از این فضا استفاده کنه .

فایل سیستم های خانواده ext مثل ext2 , 3 و ۴ نیاز به چک شدن تو یک بازه خاصی رو دارن اینکار برای شناسایی اررور هاییه که احتمالا تو فایل سیستم به وجود اومده . این چک شدن قبل از mount شدن فایل سیستم انجام میگیره . متغییری تعیین کننده این بازه Maximum mount count هست . Mount count تعداد دفعاتی که فایل سیستم مونت شده رو نگه میداره وقتی این مقدار به متغییر ماکسیمم میرسه باید دیسک چک قبل از mount انجام بگیره . در حال حاضر مقدار این قسمت -۱ هست که یعنی هیچ وقت دیسک چک انجام نشه . البته که این مواردو میشه تغییر داد برای مثال در ادامه فضای رزرو شده و مقدار ماکسیمم رو تغییر میدیم .

من میخوام که فضای رزرو شده رو به ۱۰ درصد و ماکسیمم تعداد دفعاتی که فایل سیستم بدون چک شدن می تونه مونت بشه رو به ۱۰ تغییر بدم :

sudo tune2fs -m 10 -c 10 /dev/sdc1 

tune2fs 1.45.5 (07-Jan-2020)
Setting maximal mount count to 10
Setting reserved blocks percentage to 10% (197529 blocks)

اگه یه بار دیگه با dump2fs چک کنید متوجه میشید که مقادیر مورد نظرمون آپدیت شدن . خب ور رفتن با فایل سیستم ها تا اینجا کافیه حالا با mount کردن آشنا میشیم .

Mounting FileSystems

دستکاری فایل سیستم و ست کردن مقادیری که میخواییم مهمه ولی هدف اینکه از اون فایل سیستم استفاده کنیم روش فایل ایجاد کنیم و غیره . برای اینکه از فایل سیستم ها استفاده کنیم به اصطلاح باید اونارو mount کنیم . که معمولا به یه دایرکتوری mount می کنیم این عمل می تونه فقط یک بار رخ بده یا هر بار پس از ریبوت خودکار اینکار انجام بشه . شکل کلی دستور mount به صورت زیره :‌

mount [device] [mountpoint] 

البته آپشن ها و پارامتر های متنوعی داره که ازش می گذریم . الآن اگه بخوام فایل سیستمی که رو فلش دیسکم ساختم رو مونت کنم به این صورت خواهد بود.( معمولا برای مونت کردن به دسترسی روت نیاز دارید )

sudo mount /dev/sdc1  ~/flashdisk 

فایل سیستمارو هر جایی که عشقون کشید می تونید مونت کنید . در واقع حتی می تونید فایل سیستمی رو به عنوان یکی از دایرکتوری های اصلی که لینوکس واسه کارکرد عادیش لازم داره هم مونت کنید . همین ویژگی هست که لینوکس رو خیلی انعطاف پذیر تر می کنه . ( البته این کار نیاز به کمی کارای اضافی داره یه راست نرید تو کارش :/ )

لینوکس یه لیست از دیوایس هایی که در حاضر مونت شده رو تو یه فایل نگه میداره .

less /etc/mtab 

خب حالا استفاده تون تموم شده و میخوایید که فایل سیستم رو unmount کنید مشکلی نیست مث آب خوردن با دستور umount می شه اینکارو کرد هم می تونید آدرس بلاک دیوایس رو بدید یا mount point رو با هر دو کار می کنه .

sudo umount ~/flashdisk 

خب حالا رسیدیم به قسمتی که میخواییم فایل سیستمارو به صورت اتوماتیک در هنگام استارت آپ مونت بشه . برای اینکار از فایل fstab استفاده میشه بیاید یه نگا بهش بندازیم .

less /etc/fstab

UUID=ca4145fa-a492-44c3-9dd7-b0dc995a7f9d /               ext4    errors=remount-ro 0       1
# /boot/efi was on /dev/sda2 during installation
UUID=00BE-6BD7  /boot/efi       vfat    umask=0077      0       1
# /home was on /dev/sdb4 during installation
UUID=90ea1ff5-6f58-414f-8d67-df77ef7fa9a6 /home           ext4    defaults        0       2
# swap was on /dev/sdb5 during installation
UUID=f372d532-05e1-4ed4-be73-7def37b42211 none            swap    sw              0       0

خب خط اول دستور مونت کردن دایرکتوری ریشه تون هست ! البته اینجا از UUID دیوایس استفاده شده که با دستور sudo blkid خیلی راحت می تونید این موردو پیدا کنید . تقریبا مثل ابزار mount دیوایس رو می نویسد مونت پوینت رو قید می کنید و آپشن هایی بر اساس نیاز براش تعیین می کنید . مثلا همون خط اول آپشنی داره به این صورت errors=remount-ro به این معنیه که اگر ارروری تو فایل سیستم ایجاد شد، فایل سیستم رو مجددا به صورت فقط خواندنی مونت کن . آپشن های زیادی اینجا میشه استفاده کرد که به نظرم یه پست دیگه میطلبه فعلا در همین حد کافیه :)

خب اگه بخواییم فایل سیستمی که ساختیم رو به این فایل اضافه کنیم به اینصورت خواهد بود . کافیه این خطو آخر فایل اضافه کنید و بعد از هر بار ریبوت فایل سیستم مورد نظرم به مونت پوینتی که میخوایم مونت میشه .

/dev/sdc1 /home/user/flashdisk ext2 defaults 0 0 

خب به نظرم تا همین جا کافیه . خوشحال میشم مارو به دوستانتون معرفی کنید انتقاد پیشنهادی هم داشتید ما جنبه مون بالاس کامنت کنید حتما میخونیم . :-)