File systems and basic Linux concepts
45 min · Intermediate
Need help? Ask a tutor on WhatsApp (opens in a new tab)Most servers that run Python applications run Linux, so interviews ask "what is an inode?" and "how do you find the process using port 8080?" in the same round. The interviewer is checking theory and hands-on habits together.
Files, directories, inodes and allocation methods
Inode is the record a file system keeps for each file: size, owner, permissions, timestamps, link count and pointers to the data blocks, but not the file name.
The program below shows how one file of four blocks is found under contiguous, linked and indexed allocation, and how many blocks each method reads to reach the third one.
Example 1 · Three allocation methods for one file
# A file "marks.csv" that needs 4 blocks.start, length = 14, 4blocks = range(start, start + length)print("Contiguous: start", start, "length", length, "-> blocks", *blocks)
next_block = {9: 16, 16: 1, 1: 25, 25: -1} # FAT-style chainb, chain = 9, []while b != -1: chain.append(b) b = next_block[b]print("Linked: start 9 -> blocks", *chain)
index_block = [9, 16, 1, 25]print("Indexed: index block holds", index_block)print(f" 3rd block directly: {index_block[2]} (linked must read 3 blocks to reach it)")Contiguous: start 14 length 4 -> blocks 14 15 16 17 Linked: start 9 -> blocks 9 16 1 25 Indexed: index block holds [9, 16, 1, 25] 3rd block directly: 1 (linked must read 3 blocks to reach it)
What this code does
- Contiguous needs only a start and a length, but the four blocks must be free side by side. Linked can use any free blocks, but reaching the third block means following the chain.
- Indexed allocation stores every block number in one place, so any block is one lookup away. Inodes use this idea with direct and indirect pointers.
A file is a named collection of data and a directory is a special file that maps names to inode numbers. The OS must also decide which disk blocks a file uses:
- Contiguous allocation gives consecutive blocks: fast, but external fragmentation and hard to grow.
- Linked allocation chains blocks with pointers: no fragmentation but slow random access; FAT keeps the chain in a table.
- Indexed allocation keeps all pointers in an index block: fast random access, which is what inodes do with direct and indirect pointers.
A hard link is another name for the same inode (the data stays until the link count reaches 0). A soft link is a small file that holds a path and breaks if the target is deleted. ls -i shows inode numbers; df -i shows how many inodes are free. From Python, os.stat(path) returns the inode number (st_ino), the link count (st_nlink) and the mode (st_mode) of a file.
Find the bug
Weak spoken answers
Each spoken answer has one wrong sentence. Click it.
Answer to "Hard link vs soft link?"
Round 1 of 2Disk scheduling at a glance (FCFS, SSTF, SCAN)
Seek time is the time the disk head needs to move to the cylinder that holds the requested data; disk scheduling orders requests to reduce it.
The program below runs FCFS, SSTF, SCAN, C-SCAN and LOOK on the classic queue 98, 183, 37, 122, 14, 124, 65, 67 with the head at 53, and prints the total head movement of each.
Example 2 · Total head movement for FCFS, SSTF, SCAN, C-SCAN and LOOK
def fcfs(head, reqs): moved = 0 for r in reqs: moved += abs(r - head) head = r return moved
def sstf(head, reqs): left, moved = reqs[:], 0 while left: best = min(left, key=lambda r: abs(r - head)) moved += abs(best - head) head = best left.remove(best) return moved
reqs = [98, 183, 37, 122, 14, 124, 65, 67]head, max_cyl = 53, 199lowest, highest = min(reqs), max(reqs)below = max(r for r in reqs if r < head)
scan_down = head + highest # to 0, then up to 183cscan_up = (max_cyl - head) + max_cyl + below # to 199, jump to 0, up to 37look_down = (head - lowest) + (highest - lowest) # to 14, then up to 183
print("FCFS: ", fcfs(head, reqs))print("SSTF: ", sstf(head, reqs))print("SCAN (towards 0): ", scan_down)print("C-SCAN (upwards): ", cscan_up, "(including the 199-cylinder jump)")print("LOOK (towards 0): ", look_down)FCFS: 640 SSTF: 236 SCAN (towards 0): 236 C-SCAN (upwards): 382 (including the 199-cylinder jump) LOOK (towards 0): 208
What this code does
- SSTF goes 53 → 65 → 67 → 37 → 14 → 98 → 122 → 124 → 183. SCAN goes down to 0 and then up to 183: 53 + 183 = 236.
- Textbooks differ on whether the C-SCAN return jump counts as head movement; state your assumption. LOOK saves the trip to cylinder 0 by turning at 14.
On a hard disk, moving the head between cylinders is the slowest part of an access. FCFS serves requests in arrival order. SSTF (shortest seek time first) always goes to the nearest request; it is efficient but can starve far requests. SCAN (the elevator algorithm) sweeps to one end serving requests on the way, then reverses.
C-SCAN sweeps in one direction only and jumps back, giving more uniform waiting; LOOK and C-LOOK turn at the last request instead of the disk edge. FCFS moves 640 cylinders here, SSTF 236 and SCAN towards 0 also 236. On SSDs there is no moving head, so this matters much less.
Predict the output
Head movement
The head is at 20 and the queue is 35, 10, 45. Pick the total movement.
Round 1 of 2
FCFS serves the requests in the order they arrived.
Linux basics: kernel, shell, permissions and processes
File permissions give read (4), write (2) and execute (1) rights separately to the owner, the group and others; adding the values per group gives one octal digit, so 755 is rwxr-xr-x.
Linux is a Unix-like OS you control through a shell such as bash. The commands below change and read permissions and stop a process; the program after them turns chmod numbers into rwx letters.
$ chmod 755 deploy.sh$ ls -l deploy.sh-rwxr-xr-x 1 ravi devs 812 Jun 10 10:15 deploy.sh$ chmod u=rw,g=r,o= notes.txt # same as chmod 640$ ps aux | grep pythonravi 4120 2.1 6.3 ... python worker.py$ kill 4120 # SIGTERM: ask the app to shut down cleanlyExample 3 · Turning chmod numbers into rwx
def rwx(digit): return ("r" if digit & 4 else "-") + ("w" if digit & 2 else "-") + ("x" if digit & 1 else "-")
def symbolic(octal): return "".join(rwx(int(c)) for c in octal)
for mode in ["755", "644", "600", "700", "777", "640"]: print("chmod", mode, "->", symbolic(mode))chmod 755 -> rwxr-xr-x chmod 644 -> rw-r--r-- chmod 600 -> rw------- chmod 700 -> rwx------ chmod 777 -> rwxrwxrwx chmod 640 -> rw-r-----
What this code does
- Each octal digit is one group (owner, group, others), and its bits are r = 4, w = 2, x = 1. 7 = 4 + 2 + 1 = rwx; 5 = 4 + 1 = r-x.
- 644 is the usual mode for normal files, 755 for scripts and directories, 600 for private keys. 777 gives everyone write access and is almost always a mistake on a server. In Python,
os.chmod(path, 0o755)sets the same mode; the0oprefix marks an octal number.
Everything is a file, including devices under /dev, and the directory tree starts at /. chmod 755 run.sh means owner rwx (7), group r-x (5), others r-x (5). Each process has a PID: ps lists processes, kill PID sends SIGTERM (a polite stop request that the program can handle) and kill -9 PID sends SIGKILL, which cannot be caught or ignored.
Common modes: 644 for normal files, 755 for scripts and directories, 600 for private keys. 777 gives everyone write access and is almost always a mistake on a server.
Predict the output
Letters to number
The code adds 4, 2 and 1 for every letter that is not a dash.
Which chmod number does rwxr-x--- stand for?
Common Linux commands asked in interviews
Pipe connects the output of one command to the input of the next with the | symbol, so small tools can be chained into one command.
Linux command questions check whether you can find your way on a server: read logs, search, check disk and memory, and manage processes. The commands below show the habits; the next example investigates a slow server.
$ tail -f logs/app.log | grep ERROR # follow a log, keep only errors$ df -h /Filesystem Size Used Avail Use% Mounted on/dev/sda1 50G 31G 17G 65% /$ find . -name "*.log" -mtime +7 -delete # delete logs older than 7 days$ ss -tlnp | grep 8080 # is anything listening on 8080?Example 4 · Investigating a slow server from the shell
$ uptime 10:42:07 up 12 days, 3:01, 1 user, load average: 3.92, 3.10, 2.40$ free -h total used free shared buff/cache availableMem: 7.7Gi 6.9Gi 210Mi 12Mi 620Mi 540Mi$ ps aux --sort=-%mem | head -3USER PID %CPU %MEM COMMANDravi 4120 85.0 62.1 python worker.pyravi 3999 1.2 2.0 node server.js$ du -sh logs/4.1G logs/Load is high, only 540 MiB is available, and the Python process uses 62% of RAM. Next steps: check whether the worker keeps growing (a leak, or a huge list held in memory), read its logs, and rotate the 4.1 GB of logs.
What this code does
uptimeshows the load average for 1, 5 and 15 minutes;free -hshows memory; sortingpsby memory finds the biggest process.- Your numbers will differ. The habit to show in an interview: measure first (CPU, memory, disk), then name the next command, not a guess.
Know what each command does and one common option:
- Files:
ls -la,cd,pwd,cp,mv,rm -r,mkdir -p,cat,less,head -n 20,tail -f app.log. - Search:
grep -rn "ERROR" logs/,find . -name "*.py",wc -l. - System:
df -h(disk),du -sh *(folder sizes),free -h(memory),toporhtop,uname -a. - Processes and network:
ps aux,kill,nohup cmd &,jobs,ss -tlnp(listening ports),curl.
Order of execution
Investigate a slow server
Put the checks in the order a calm engineer would run them.
Interview questions with model answers
Indexed allocation keeps all of a file's block pointers in an index block, so any block is one lookup away; an inode extends it with direct and indirect pointers.
Interview numericals here are permissions, disk-head movement and maximum file size. The program below computes the maximum file size an inode can address with 4 KB blocks and 4-byte pointers.
Example 5 · Maximum file size with inode pointers
block = 4096 # 4 KB blockspointer = 4 # 4-byte block numbersper_block = block // pointer # pointers in one block: 1024
direct = 12single = per_blockdouble = per_block ** 2triple = per_block ** 3blocks = direct + single + double + triple
print("Pointers per block:", per_block)print("Direct:", direct * block, "bytes (48 KB)")print("Single indirect:", single * block, "bytes (4 MB)")print("Double indirect:", double * block, "bytes (4 GB)")print("Triple indirect:", triple * block, "bytes (4 TB)")print("Max file size:", blocks * block, "bytes (about 4 TB)")Pointers per block: 1024 Direct: 49152 bytes (48 KB) Single indirect: 4194304 bytes (4 MB) Double indirect: 4294967296 bytes (4 GB) Triple indirect: 4398046511104 bytes (4 TB) Max file size: 4402345721856 bytes (about 4 TB)
What this code does
- Each indirect level multiplies by 1024 pointers per block, so the triple-indirect part dominates. Small files use only the 12 direct pointers and need no extra block reads.
- This is the classic Unix (ext2-style) layout used in exam questions. Modern ext4 uses extents and other limits, so real maximums differ.
Each indirect level multiplies by the number of pointers per block, so the triple-indirect part dominates, and small files use only the 12 direct pointers. Practise saying the four facts aloud:
- An inode holds metadata and block pointers, not the name.
- A hard link shares the inode; a soft link stores a path.
- r = 4, w = 2, x = 1; 755 = rwxr-xr-x and 644 = rw-r--r--.
- SIGTERM can be handled; SIGKILL (-9) cannot.
Predict the output
How many blocks can a file have?
1 KB blocks, 4-byte pointers, 10 direct pointers, one single and one double indirect block.
Pick the number of data blocks one file can address.
Next step
Check your understanding
12 quick questions