df مکمل مگر du نہیں: ڈسک کی جگہ کہاں گئی؟
VPS میں `df` مکمل اور `du` کم دکھائے تو حذف شدہ مگر کھلی file تلاش کریں۔ `lsof` سے process معلوم کریں، reboot کے بغیر جگہ خالی کریں، اور دیگر وجوہات سمجھیں۔
df مکمل اور du مختلف نتیجہ کیوں دکھاتا ہے
df ڈسک کو مکمل دکھاتا ہے، جبکہ du جگہ تلاش نہیں کر پاتا کیونکہ کوئی process ایسی file کھولے رکھتا ہے جسے حذف کر دیا گیا ہے۔ File حذف کرنے سے directory میں موجود اس کا نام ختم ہو جاتا ہے۔ Data blocks صرف اس وقت release ہوتے ہیں جب اس inode کی طرف اشارہ کرنے والا آخری open file descriptor بند ہو جائے۔ du file names کو scan کرتا ہے، اس لیے اسے یہ جگہ نظر نہیں آتی۔ df filesystem سے پوچھتا ہے کہ کتنے blocks allocated ہیں، اس لیے وہ اس file کو اب بھی شمار کرتا ہے جس کا نام باقی نہیں رہا۔
یہ guide پہلے سے installed tools کے ذریعے ایک سادہ Ubuntu VPS پر اس صورت حال کو دوبارہ پیدا کرتی ہے، /proc کے ذریعے وہ process تلاش کرتی ہے جو file کو کھولے ہوئے ہے، اور reboot کیے بغیر جگہ خالی کرتی ہے۔ اسی علامت کی دیگر وجوہات بھی آگے بیان کی گئی ہیں: inode table میں کوئی free entry نہ ہونا، mount point کے نیچے چھپی ہوئی files، اور root کے لیے reserved blocks۔
ہر command چلائیں اور اپنا output پڑھیں۔ Values آپ کی disk پر منحصر ہیں، اس لیے guide میں دی گئی کسی figure سے موازنہ کرنے کے بجائے اپنی machine پر before اور after نتائج کا موازنہ کریں۔
What df counts and what du counts
df (disk free) asks each mounted filesystem for its own accounting: how many blocks exist, how many are allocated, how many are free. It never opens a directory. The answer covers every allocated block, including blocks belonging to a file that no directory entry points at.
du (disk usage) does the opposite. It starts at a path you give it, reads directories, stats every entry it finds, and adds up the blocks. A file with no name is invisible to it. So is any directory it is not allowed to read, which is why an ordinary user gets a smaller total than root does. Run du under sudo before you conclude anything from the comparison.
Two options matter every time you compare the two.
-xkeepsduon one filesystem. Without it,du /walks into every filesystem mounted below/and produces a total thatdf /was never measuring.-sprints one summary line per argument instead of one line per directory.
That gives the pair to run side by side on the filesystem you care about.
df -h /
sudo du -xhs / 2>/dev/nulldf answers immediately. du takes minutes on a large filesystem, because it stats every file on the way. When the two totals are far apart, and du ran as root with -x, the missing space is allocated to something that has no name.
جان بوجھ کر فرق دوبارہ پیدا کریں
یہ کام test VPS پر کریں۔ ذیل کے تمام commands bash اور coreutils سے متعلق ہیں، اس لیے کچھ بھی install نہیں ہوگا۔
اس filesystem کی ابتدائی حالت record کریں جس میں /var/tmp موجود ہے۔
cd /var/tmp
df -h .
df --output=used -B1 .دوسرا command استعمال شدہ bytes کو بغیر rounding کے دکھاتا ہے، اس لیے آخر میں ہونے والی جانچ بالکل درست رہتی ہے۔
اب ایک file بنائیں۔ اس کا size machine کی رپورٹ کردہ free space سے حاصل ہوگا، اس لیے یہ demonstration آپ کی موجود disk کے مطابق رہے گی۔
free=$(df --output=avail -B1 . | tail -n 1)
fallocate -l $((free / 10)) ghost.bin
ls -l ghost.bin
df -h .$(...) command substitution ہے: shell اس کے اندر موجود command چلاتا ہے، اور اس کا output free کی value بن جاتا ہے۔ اگر یہ syntax آپ کے لیے نیا ہے تو bash میں command substitution میں اس کی مکمل وضاحت موجود ہے۔ fallocate اصل blocks کو data لکھے بغیر reserve کرتا ہے، اسی لیے یہ فوراً مکمل ہوجاتا ہے۔ ایسے filesystem پر جو اسے support نہ کرتا ہو، command fail ہوجاتا ہے، اور head -c $((free / 10)) /dev/zero > ghost.bin bytes لکھ کر یہی کام کرتا ہے۔
اس df -h . کا موازنہ پہلے record کیے گئے output سے کریں۔ used column بڑھ گیا ہے اور available column کم ہوگیا ہے۔
اب کسی دوسرے process سے file کو open رکھیں، پھر اسے delete کریں۔
sleep infinity < ghost.bin &
holder=$!
rm ghost.bin
ls -l ghost.bin
df -h .
sudo du -xhs . 2>/dev/nullاصل trick redirection میں ہے۔ sleep infinity < ghost.bin & ایک background process شروع کرتا ہے جس کا standard input وہ file ہوتی ہے، اس لیے shell file کھول کر descriptor sleep کے حوالے کر دیتا ہے، جو اسے open رکھتا ہے۔ $! اس background job کی process ID محفوظ کرتا ہے۔ rm پھر نام کو حذف کر دیتا ہے، جبکہ descriptor اب بھی open رہتا ہے۔
Output پڑھیں۔ ls کو file نہیں ملتی، کیونکہ نام ختم ہوچکا ہے۔ du تقریباً ابتدائی حالت پر واپس آجاتا ہے، کیونکہ یہ names کے ذریعے چلتا ہے۔ df میں کوئی تبدیلی نہیں آتی، کیونکہ blocks اب بھی allocated ہیں۔ اب filesystem اور directory tree ایک دوسرے سے مختلف حالت دکھا رہے ہیں، اور ان کے درمیان موجود فرق وہ file ہے جسے آپ نے ابھی delete کیا ہے۔
حذف شدہ فائل کو کھلا رکھنے والے process کو تلاش کریں
ہر open file descriptor، /proc/<pid>/fd/ کے تحت، اس فائل کی طرف symbolic link کے طور پر ظاہر ہوتا ہے جس سے وہ متعلق ہوتا ہے۔ جب فائل unlink ہو جاتی ہے تو kernel اس link کے target کو deleted کے طور پر نشان زد کر دیتا ہے۔ اس لیے holder تلاش کرنے کا مطلب ایسی link تلاش کرنا ہے جس کے target میں یہ marker موجود ہو۔
sudo find /proc/[0-9]*/fd -lname '*(deleted)' -printf '%p -> %l\n' 2>/dev/null-lname symbolic link کے نام کے بجائے اس کے target سے match کرتا ہے، %p descriptor کا path دکھاتا ہے، اور %l بتاتا ہے کہ وہ کس طرف اشارہ کر رہا ہے۔ process ID اس path کا دوسرا حصہ ہوتا ہے جو یہ command دکھاتی ہے۔ اسے sudo کے ساتھ چلائیں، کیونکہ بصورت دیگر آپ صرف اپنے processes کے لیے /proc/<pid>/fd پڑھ سکتے ہیں۔ stderr redirect ان processes کے متعلق غیر ضروری output ختم کر دیتا ہے جو find کے چلنے کے دوران ختم ہو جاتے ہیں۔
مصروف server کسی بھی وقت کئی deleted files کھلا رکھتا ہے، اور ان میں سے زیادہ تر چھوٹی اور بے ضرر ہوتی ہیں۔ انہیں size کے لحاظ سے sort کریں تاکہ صرف اہم files فہرست کے اوپر رہیں۔
sudo bash -c 'for fd in /proc/[0-9]*/fd/*; do
target=$(readlink "$fd" 2>/dev/null) || continue
case "$target" in
*"(deleted)") echo "$(stat -Lc %s "$fd" 2>/dev/null) $fd $target" ;;
esac
done' | sort -rn | headstat -L link کو خود inode تک follow کرتا ہے، اس لیے %s اس file کا size بتاتا ہے جس کا اب کوئی نام نہیں رہا۔ اس number کے لحاظ سے sorting کرنے سے سب سے بڑی file پہلے آ جاتی ہے۔
اب سب سے اوپر موجود descriptor کے پیچھے process کی شناخت کریں۔ فہرست کے اوپر موجود path میں وہ دونوں numbers شامل ہیں جن کی آپ کو ضرورت ہے، اس لیے پہلے انہیں variables میں رکھیں۔ PID اور N کی جگہ اپنی listing میں دکھائے گئے values استعمال کریں۔
pid=PID
n=N
ps -o pid,user,etime,args -p "$pid"
sudo stat -L "/proc/$pid/fd/$n"ps program کا نام اور اس کے چلنے کا دورانیہ دکھاتا ہے۔ stat -L deleted inode کا size اور allocated blocks کی تعداد دکھاتا ہے۔ دونوں مل کر اس اہم سوال کا جواب دیتے ہیں: کون سی service اس file کو زندہ رکھے ہوئے ہے۔
اگر machine پر پہلے سے lsof موجود ہو تو sudo lsof +L1 ان open files کی فہرست بناتا ہے جن کا link count صفر ہو چکا ہے، اور sizes کو ایک table میں دکھاتا ہے۔ یہ minimal Ubuntu image میں موجود نہیں ہوتا، اور خالی space کے بغیر filesystem پر package install کرنا خود بھی ناکام ہو سکتا ہے۔ اس لیے /proc والا walk وہ طریقہ ہے جو ہمیشہ کام کرتا ہے۔
ریبوٹ کے بغیر جگہ خالی کریں
ریبوٹ واقعی مسئلہ حل کر دیتا ہے، لیکن یہ پہلا قدم نہیں ہونا چاہیے: اس سے service بند ہو جاتی ہے اور شواہد ضائع ہو جاتے ہیں۔ کم مداخلت والے 4 طریقے موجود ہیں۔ انہیں اسی ترتیب سے آزمائیں۔
پہلے data کو copy کر لیں، اگر آپ اسے محفوظ رکھنا چاہتے ہیں۔ descriptor path کو پڑھنے سے live inode پڑھا جاتا ہے۔
sudo cp /proc/<pid>/fd/<n> /root/recovered.logیہ وہ واحد صورت ہے جس میں deleted file واپس حاصل کرنا آسان ہوتا ہے۔ اسی لیے rm -rf سے حذف شدہ files کو recover کرنا اس سوال سے شروع ہوتا ہے کہ آیا کوئی process اب بھی file کو open رکھے ہوئے ہے۔ آخری descriptor بند ہوتے ہی یہ راستہ ختم ہو جاتا ہے۔
دوسرا طریقہ یہ ہے کہ descriptor کے ذریعے file خالی کر دیں۔ /proc path اسی inode تک پہنچاتا ہے، اس لیے اسے truncate کرنے سے process چلتا رہتے ہوئے blocks release ہو جاتے ہیں۔
sudo truncate -s 0 "/proc/$pid/fd/$n"
df -h /یہ طریقہ اس وقت درست طور پر کام کرتا ہے جب writer نے file کو append mode میں open کیا ہو، کیونکہ ہر write اس وقت file کے موجودہ اختتام پر جاتی ہے۔ اگر ایسا نہ ہو تو process اپنا پرانا write offset برقرار رکھتا ہے۔ اس لیے اس کی اگلی write file میں بہت آگے جا کر ہوتی ہے اور شروع میں hole کے ساتھ file دوبارہ بن جاتی ہے۔ Hole کے لیے space allocate نہیں ہوتی، اس لیے blocks خالی رہتے ہیں اور df وہ space برقرار رکھتا ہے جو اس نے ابھی واپس کی ہے۔ صرف size دوبارہ بڑھتی ہے: process کے write کرنے کے بعد sudo stat -L "/proc/$pid/fd/$n" دوبارہ چلائیں۔ یہ پرانی size دکھائے گا، جبکہ block count اس سے مطابقت نہیں رکھے گا۔ اگر size بھی صفر سے شروع کرنی ہو تو process restart کریں۔
تیسرا طریقہ یہ ہے کہ service سے اپنے logs دوبارہ open کرنے کو کہیں۔ کسی daemon کی log file اس کے چلتے ہوئے delete ہو جائے تو یہی اس مسئلے کی عام حقیقی صورت ہے۔ بہت سے daemons signal ملنے پر اپنی log files دوبارہ open کرتے ہیں: nginx کے لیے SIGUSR1 اور rsyslog کے لیے SIGHUP استعمال ہوتا ہے۔ اپنے سامنے موجود daemon کی documentation دیکھ کر signal کا تعین کریں، اندازہ نہ لگائیں، کیونکہ غلط daemon کو غلط signal بھیجنے سے وہ رک سکتا ہے۔
sudo systemctl kill -s USR1 nginxچوتھا طریقہ unit کو restart کرنا ہے۔ sudo systemctl restart <unit> پرانے process کے زیرِ استعمال ہر descriptor بند کر دیتا ہے، اس لیے blocks یقینی طور پر واپس آ جاتے ہیں۔ اوپر کی demonstration میں holder ایک sleep ہے جسے آپ نے خود شروع کیا تھا، اس لیے اسے ختم کرنا کافی ہے۔
kill $holder
df -h .
df --output=used -B1 .
sudo find /proc/[0-9]*/fd -lname '*(deleted)' -printf '%p -> %l\n' 2>/dev/nullاستعمال شدہ bytes کا اس value سے موازنہ کریں جو file بنانے سے پہلے record کی تھی۔ دونوں دوبارہ برابر ہیں، اور find اب آپ کے descriptor کو report نہیں کرتا۔ اسی command سے تصدیق کرنا جس نے مسئلہ تلاش کیا تھا، برقرار رکھنے کے قابل اچھی عادت ہے۔
اس value میں ہونے والی تبدیلی کو دیکھنا df کو بار بار دستی طور پر چلانے سے آسان ہے۔ watch ایک مقررہ وقفے پر command دہراتا ہے اور output کو اسی جگہ دوبارہ دکھاتا ہے، اس لیے watch df -h / used column میں ہونے والی تبدیلی دکھاتا ہے جب space واپس آتی ہے۔
جب totals باہم مطابقت رکھتے ہوں اور disk پھر بھی full ہو
اگر df اور root du -x ایک دوسرے سے مطابقت رکھتے ہوں تو اس میں deleted file شامل نہیں ہے۔ باقی وجوہات نوعیت میں مختلف ہیں، اور ہر وجہ کی اپنی جانچ ہے۔
انodes ختم ہو گئے، blocks نہیں
inode ایک فائل کا metadata رکھتا ہے۔ ext4 فائل سسٹم بناتے وقت inodes کی ایک مقررہ تعداد بناتا ہے، اس لیے فائل سسٹم میں free blocks موجود ہونے کے باوجود inodes ختم ہو سکتے ہیں۔ اس کے بعد نئی فائلیں بنانے میں ناکامی ہوتی ہے، حالانکہ df -h میں جگہ موجود دکھائی دیتی ہے۔
df -h /
df -i /پہلی کمانڈ blocks گنتی ہے اور دوسری inodes گنتی ہے۔ دونوں کے use کالم کا موازنہ کریں۔ اگر block use کم ہو اور inode use اپنی حد تک پہنچ چکا ہو تو مسئلہ بہت بڑی تعداد میں موجود بہت چھوٹی فائلیں ہیں۔
df ایک ہی invocation میں -i اور --output کو مسترد کرتا ہے، اس لیے جب آپ raw counts پڑھنا یا کسی دوسری کمانڈ کو دینا چاہتے ہوں تو inode fields کو نام سے منتخب کریں اور -i شامل نہ کریں۔
df --output=itotal,iused,iavail,ipcent /یہ columns وہی accounting دکھاتے ہیں جو df -i پرنٹ کرتا ہے، لیکن ایسی شکل میں جسے آپ الگ الگ پڑھ سکتے ہیں۔
فائلوں کو bytes کے بجائے entries گن کر تلاش کریں۔
sudo du --inodes -x -d 1 / 2>/dev/null | sort -rn | headجو directory سب سے زیادہ استعمال دکھائے، اسی پر ایک level نیچے یہی کمانڈ دوبارہ چلائیں، یہاں تک کہ آپ اس tree تک پہنچ جائیں جو فائلیں بنا رہا ہے۔ اگر آپ کا du، --inodes کو support نہیں کرتا تو sudo find /var -xdev -type f | wc -l subtree کو سست طریقے سے گنتا ہے۔
حل یہ ہے کہ ان فائلوں کو delete یا move کریں۔ آپ موجودہ ext4 فائل سسٹم میں inodes شامل نہیں کر سکتے، کیونکہ ان کی تعداد mkfs وقت مقرر ہو جاتی ہے۔ اس لیے تعداد بڑھانے کا مطلب فائل سسٹم دوبارہ بنانا اور backup سے restore کرنا ہے۔ XFS ضرورت کے مطابق inodes allocate کرتا ہے، اس لیے اسے اسی طرح کی fixed ceiling کا سامنا نہیں ہوتا۔ جو machine containers چلاتی ہے، وہ دونوں limits تک عموماً زیادہ جلد پہنچتی ہے، کیونکہ image layers میں بہت سی چھوٹی فائلیں ہوتی ہیں۔ ایسی machine پر VPS میں Docker کے disk usage کو prune کرنا مخصوص حل ہے، اور اس سے filesystem کی عمومی sweep کے مقابلے میں کہیں زیادہ جگہ واپس ملتی ہے۔
ماؤنٹ پوائنٹ کے نیچے چھپی ہوئی فائلیں
کسی directory میں اس پر کچھ mount ہونے سے پہلے فائلیں موجود ہو سکتی ہیں۔ اس directory پر filesystem mount کریں تو نیچے موجود فائلیں اپنی جگہ رہتی ہیں: ان کے لیے storage مختص رہتا ہے، df میں شمار ہوتی ہیں، لیکن نام کے ذریعے قابل رسائی نہیں رہتیں۔ du انہیں نہیں دیکھ سکتا کیونکہ mount ان فائلوں کو ڈھانپ دیتا ہے۔
اسے tmpfs کے ساتھ دکھائیں، جس کے لیے اضافی disk درکار نہیں ہوتی۔ اس حصے کے لیے ایسی machine درکار ہے جہاں آپ کو mount کرنے کی اجازت ہو، اس لیے یہ KVM VPS پر کام کرتا ہے۔
sudo mkdir -p /srv/covered
sudo cp /etc/services /srv/covered/
ls /srv/covered
sudo mount -t tmpfs tmpfs /srv/covered
ls /srv/covered
sudo umount /srv/covered
ls /srv/coveredدرمیانی ls ایک خالی directory دکھاتا ہے۔ copy کہیں نہیں گئی: وہ اب بھی root filesystem پر موجود ہے اور unmount کرتے ہی دوبارہ نظر آ جائے گی۔ اب ایسی service کا تصور کریں جو کسی volume کے اس path پر mount ہونے سے پہلے ایک ماہ تک اسی path میں logs لکھتی رہی ہو۔
چلتے ہوئے server پر اصل فائلیں تلاش کرنے کے لیے root filesystem کو دوسری بار کسی اور جگہ mount کریں۔ bind mount ایک filesystem کو اس کے اندر mount کیے گئے filesystems کے بغیر دکھاتا ہے۔
sudo mkdir -p /mnt/rootcheck
sudo mount --bind / /mnt/rootcheck
sudo du -xhs /mnt/rootcheck/* 2>/dev/null | sort -h
sudo umount /mnt/rootcheckاس listing میں جو چیزیں نظر آئیں لیکن معمول کے path کے تحت موجود نہ ہوں، وہ mount point کے نیچے چھپی ہوئی ہیں۔ کام مکمل ہونے پر bind mount کو unmount کریں، ورنہ بعد میں du بغیر -x چلانے سے وہی فائلیں دو مرتبہ شمار ہوں گی۔
root کے لیے مخصوص بلاکس
ext4 اپنے بلاکس کا ایک حصہ root صارف کے لیے مخصوص رکھتا ہے، تاکہ ڈسک مکمل بھر جانے پر root صارف مشین میں لاگ ان کرکے اس کی مرمت کر سکے۔ عام صارف کے طور پر چلنے والا process پہلے اس حد تک پہنچتا ہے، جبکہ df میں اب بھی تھوڑی جگہ نظر آتی ہے۔ اپنے filesystem پر یہ setting پڑھیں، default فرض نہ کریں۔
dev=$(df --output=source / | tail -n 1)
sudo tune2fs -l "$dev" | grep -i 'block count'یہ کمانڈ total block count اور reserved block count کو ایک ہی units میں دکھاتی ہے، اس لیے دونوں کا ratio براہِ راست معلوم کیا جا سکتا ہے۔ df available column کو اس جگہ کے طور پر دکھاتا ہے جسے عام صارف اب بھی استعمال کر سکتا ہے۔ اسی لیے used اور available کو جمع کرنے پر size سے کم قدر حاصل ہوتی ہے۔ یہ فرق reserve ہے۔
اسے sudo tune2fs -m <percent> "$dev" سے تبدیل کریں۔ تبدیلی فوری طور پر لاگو ہوتی ہے اور remount کی ضرورت نہیں ہوتی۔ الگ data filesystem پر reserve کم کرنا مناسب ہے۔ root filesystem پر اتنی جگہ ضرور مخصوص رہنے دیں کہ root صارف لکھ سکے، کیونکہ مکمل طور پر بھرا ہوا root filesystem ٹھیک کرنا بہت مشکل ہوتا ہے۔ tune2fs ext2، ext3 اور ext4 پر کام کرتا ہے۔ XFS میں اس setting کا کوئی متبادل نہیں ہے۔
جہاں du اکیلا استعمال کرنے پر گمراہ کر سکتا ہے
du کی چار عادتیں ایسے مجموعے دکھاتی ہیں جو غلط معلوم ہوتے ہیں۔
- Hard links:
duکسی inode کو صرف ایک بار شمار کرتا ہے، چاہے متعدد نام اس کی طرف اشارہ کر رہے ہوں۔ اس لیے hard links سے بھرے درخت میں رپورٹ کیا گیا مجموعہ اس کی فائلوں کے مجموعے سے کم ہوتا ہے۔ - Sparse files:
duحقیقت میں مختص کیے گئے blocks کی اطلاع دیتا ہے، جبکہls -lظاہری سائز کی اطلاع دیتا ہے۔ دوسرا عدد دیکھنے کے لیے--apparent-sizeشامل کریں۔ - Permissions: عام صارف کے طور پر چلانے پر
duان چیزوں کو چھوڑ دیتا ہے جنہیں وہ پڑھ نہیں سکتا، اس لیے کم مجموعہ رپورٹ کرتا ہے۔ اس کی دکھائی گئی errors وہی ہیں جنہیں لوگ/dev/nullکی طرف redirect کر کے پڑھنا بند کر دیتے ہیں۔ - Filesystem boundaries:
-xکے بغیرdu /،/کے نیچے mount کیے گئے ہر filesystem کو شمار کرتا ہے، اس لیے اس کا مجموعہdf /کی رپورٹ سے زیادہ ہو سکتا ہے۔
df کی بھی ایک عادت جاننا مفید ہے۔ یہ ہر filesystem کی الگ رپورٹ دیتا ہے، اس لیے اسے اسی exact path پر چلائیں جہاں ناکام write کا ہدف موجود ہے۔ ایک الگ /boot اپنی رفتار سے بھرتا ہے، کیونکہ kernel packages جمع ہوتے رہتے ہیں، اور Ubuntu پر پرانے kernels ہٹانا / پر جگہ خالی کرنے سے مختلف کام ہے۔
حقیقی واقعے کے لیے کام کرنے کا ترتیب وار طریقہ
df -h <path>اورdf -i <path>اس filesystem پر چلائیں جس پر ناکام write کا ہدف تھا، ہر بار عادتاً/پر نہیں۔sudo du -xh -d 1 <mountpoint> 2>/dev/null | sort -hچلائیں، پھر سب سے بڑی directory کے اندر جائیں۔- اگر
duاس استعمال کی وضاحت نہ کر سکے جسےdfused کے طور پر دکھاتا ہے، تو/procمیں ایسی deleted files تلاش کریں جو اب بھی open ہیں۔ - اگر دونوں کے نتائج ایک جیسے ہوں، تو filesystem کو کسی دوسرے مقام پر bind mount کریں اور mount point کے نیچے موجود files تلاش کریں۔
- اگر حد تک پہنچنے کی وجہ inode use ہو، تو bytes کے بجائے files شمار کریں۔
اس پورے طریقے میں ہر قدم ایک command ہے جس کے output کو آپ پڑھ سکتے ہیں۔ یہی اس مسئلے کو درست کرنے اور اندازے سے کام کرنے کے درمیان فرق ہے۔
FAQ
du کم جگہ کیوں دکھاتا ہے جبکہ df کو اس سے کہیں کم استعمال شدہ جگہ ملتی ہے؟
عام وجہ ایسی file ہوتی ہے جسے کسی process کے کھلے رکھنے کے دوران delete کر دیا گیا ہو۔ File حذف کرنے سے اس کا directory entry ختم ہو جاتا ہے، اس لیے du کے پاس چل کر شمار کرنے کے لیے کوئی نام نہیں رہتا۔ inode اور اس کے blocks آخری descriptor بند ہونے تک allocated رہتے ہیں، جبکہ df allocated blocks شمار کرتا ہے۔ /proc/<pid>/fd میں ایسے symbolic links تلاش کریں جن کا target deleted کے طور پر نشان زد ہو۔ اس طرح آپ کو file اور اسے کھلا رکھنے والا process دونوں مل جائیں گے۔ موازنے پر اعتماد کرنے سے پہلے تصدیق کریں کہ آپ نے du کو root کے طور پر اور -x کے ساتھ چلایا تھا، کیونکہ عام user خاموشی سے وہ directories چھوڑ دیتا ہے جنہیں وہ read نہیں کر سکتا۔
lsof کے بغیر ایسی deleted file کیسے تلاش کروں جو اب بھی کھلی ہو؟
Kernel کے open descriptors کے اپنے record سے فائدہ اٹھائیں۔ sudo find /proc/[0-9]*/fd -lname '*(deleted)' -printf '%p -> %l\n' 2>/dev/null ہر ایسے descriptor کو list کرتا ہے جو بے نام file کی طرف اشارہ کر رہا ہو، اور process ID اس path کے اندر موجود ہوتی ہے جسے یہ print کرتا ہے۔ ان descriptor paths میں سے کسی ایک پر sudo stat -Lc %s چلانے سے اس کا size معلوم ہوتا ہے۔ اس کے بعد انہیں sort کر کے متعلقہ file منتخب کی جا سکتی ہے۔ اس کے لیے کسی package کی ضرورت نہیں، جو اس وقت اہم ہے جب filesystem میں free space نہ ہو، کیونکہ ایسی حالت میں package install ہونا ناکام ہو سکتا ہے۔
کیا process ختم کیے بغیر جگہ خالی کی جا سکتی ہے؟
کبھی کبھی۔ sudo truncate -s 0 /proc/<pid>/fd/<n> descriptor کے ذریعے اسی inode تک پہنچتا ہے اور process کو چلتے رہنے دیتے ہوئے اس کے blocks release کر دیتا ہے۔ یہ طریقہ اس وقت سب سے صاف رہتا ہے جب process نے file کو append mode میں کھولا ہو، کیونکہ اس کی writes ہمیشہ موجودہ end پر جاتی ہیں۔ اگر ایسا نہ ہو تو write offset اپنی سابقہ جگہ پر رہتا ہے، اور اگلی write شروع میں hole کے ساتھ file دوبارہ بنا دیتی ہے۔ اس سے reported size دوبارہ بڑھ جاتی ہے، جبکہ hole کے نیچے والے blocks free رہتے ہیں۔ Unit کو restart کرنا، یا documentation میں درج signal کے ذریعے اسے logs دوبارہ open کرنے کا کہنا، ایسا حل ہے جس کے بعد sparse file باقی نہیں رہتی۔
df -i free space دکھاتا ہے لیکن writes اب بھی ناکام ہوتی ہیں۔ اور کیا وجہ ہو سکتی ہے؟
اسی path پر sudo tune2fs -l کے ذریعے inodes check کریں، کیونکہ free blocks والے مگر free inodes سے محروم filesystem میں نئی files reject ہو جاتی ہیں۔ یہ بھی check کریں کہ write کسی non-root user کے طور پر تو نہیں چل رہی، جبکہ ext4 filesystem میں صرف reserved blocks باقی ہوں۔ Device پر /boot یہ صورت حال دکھا دے گا۔ تصدیق کریں کہ آپ وہی filesystem read کر رہے ہیں جسے write حقیقتاً target کرتی ہے، کیونکہ الگ /var یا /، du سے آزادانہ طور پر بھر سکتا ہے۔
-x، df سے بڑا total کیوں دکھاتا ہے؟
-x کے بغیر du آپ کے دیے ہوئے path کے تحت mounted ہر filesystem میں داخل ہو جاتا ہے۔ اس طرح یہ متعدد filesystems کو جمع کرتا ہے، جبکہ df صرف ایک filesystem بیان کرتا ہے۔ Bind mounts مسئلہ مزید بڑھا دیتے ہیں، کیونکہ ایک ہی files ہر اس path کے تحت دوبارہ شمار ہوتی ہیں جہاں وہ ظاہر ہوں۔ -x شامل کریں تاکہ du ایک ہی filesystem تک محدود رہے، اور df کو بھی وہی path دیں تاکہ دونوں commands ایک ہی چیز بیان کریں۔