We've spent the last few articles looking at partition tables and file systems. We've discovered that your PC finds your FreeBSD slice by reading the BIOS partition table. That FreeBSD slice has a Unix partition table that contains the "disk packing label," which describes the layout of the filesystems on that slice. This week, we can finally take a look at inodes: what they are and what information about them is available to you on your FreeBSD system.
Let's start by taking another look at the output of the "disklabel" command from one of my FreeBSD systems; I've snipped the output to just show the layout of the partitions:
disklabel ad0 <snip> 8 partitions: # size offset fstype [fsize bsize bps/cpg] a: 102400 0 4.2BSD 0 0 0 # (Cyl. 0 - 6*) b: 270976 102400 swap # (Cyl. 6*- 23*) c: 6538455 0 unused 0 0 # (Cyl. 0 - 406) e: 40960 373376 4.2BSD 0 0 0 # (Cyl. 23*- 25*) f: 6124119 414336 4.2BSD 0 0 0 # (Cyl. 25*- 406*)
Notice that partitions "a", "e", and "f" are to be formatted with the filesystem type 4.2BSD, meaning the Berkeley fast file system (FFS). What is interesting to note is that each partition has been defined by its cylinders. That is, partition "a" uses cylinders 0-6, partition "e" uses cylinders 23-25, and partition "f" uses cylinders 25-406. The "*" means that the partition didn't begin or end exactly on a cylinder boundary.
What exactly is a cylinder? If you're a bit rusty on how hard drives work, you may find this article and its figures useful.
Basically, a hard drive is composed of a number of circular disks called platters. Each platter has been divided into circular tracks; a cylinder is the same track on all the platters. If you could separate all the cylinders on your hard drive, you would end up with a series of increasingly smaller sized rings with each ring being the thickness of your hard drive.
A partition is simply a cylinder group, or a group of adjacent cylinders logically joined into a wider, doughnut-shaped ring. If a partition is formatted with a filesystem, that filesystem will maintain one inode table to keep track of any data placed on that cylinder group. To summarize:
Each partition that has been formatted with a filesystem has three distinct areas:
The superblock describes the parameters of the filesystem, such as the number of blocks, the size of the blocks, the size of the fragments, and the number of inodes. (If you're curious as to what else is defined in the superblock, you'll find all the parameters in man 5 fs.) These parameters were determined by the newfs command and any switches you may have passed to that command when you created the filesystem. This means that if at a later date you discover that you will run out of inodes before you run out of disk blocks, you will have to recreate the filesystem in order to change these parameters. You'll need to back up your data and test your backup first, as recreating the filesystem with the newfs utility will destroy all of the existing data on that cylinder group.
After the superblock area is the area that contains all of the inode entries. Each inode entry is 128 bytes in size and contains information about the file that it represents; this information is known as the file's "metadata." You can find out for yourself what this metadata is by reading the file /usr/include/ufs/ufs/dinode.h; even though this is a C file, it is well commented and not too hard to figure out. I've summarized its contents by listing the metadata that an inode keeps track of:
Notice that the name of the file is not part of the inode's metadata. The filesystem doesn't care what the name of the file is; it only needs to know what inode number is associated with that file.
Much of a file's metadata can be viewed by doing a long directory listing. Let's take a look at the long listing for the root directory by using the ls command with the l switch:
ls -l / total 6429 -r--r--r-- 1 root wheel 4735 Nov 20 07:03 COPYRIGHT drwxr-xr-x 2 root wheel 1024 Dec 21 19:09 bin drwxr-xr-x 3 root wheel 512 Dec 21 12:27 boot drwxr-xr-x 2 root wheel 512 Dec 21 10:19 cdrom lrwxr-xr-x 1 root wheel 11 Dec 21 12:27 compat -> /usr/compat drwxr-xr-x 3 root wheel 13824 Feb 25 09:15 dev drwxr-xr-x 15 root wheel 2048 Dec 22 18:20 etc drwxr-xr-x 1 root wheel 7168 Jan 1 1980 floppy lrwxrwxrwx 1 root wheel 9 Dec 21 12:29 home -> /usr/home -r-xr-xr-x 1 root wheel 3258128 Nov 20 08:02 kernel -r-xr-xr-x 1 root wheel 3258128 Nov 20 08:02 kernel.GENERIC drwxr-xr-x 2 root wheel 512 Nov 20 06:56 mnt drwxr-xr-x 2 root wheel 2560 Dec 21 10:33 modules dr-xr-xr-x 1 root wheel 512 Feb 25 10:32 proc drwxr-xr-x 2 root wheel 512 Dec 23 08:30 root drwxr-xr-x 2 root wheel 2048 Dec 21 19:09 sbin drwxr-xr-x 4 root wheel 1024 Dec 21 10:19 stand lrwxrwxrwx 1 root wheel 11 Dec 21 12:22 sys -> usr/src/sys drwxrwxrwt 2 root wheel 512 Feb 25 09:15 tmp drwxr-xr-x 19 root wheel 512 Feb 11 19:04 usr drwxr-xr-x 18 root wheel 512 Nov 20 08:13 var
We've been given seven columns of output that represent each file's:
You should be able to recognize the first six as part of the metadata contained in each file's inode.
You can also find out the inode number of each file by adding the i switch to the ls command:
ls -li / total 6429 441 -r--r--r-- 1 root wheel 4735 Nov 20 07:03 COPYRIGHT 46 drwxr-xr-x 2 root wheel 1024 Dec 21 19:09 bin 6323 drwxr-xr-x 3 root wheel 512 Dec 21 12:27 boot 44 drwxr-xr-x 2 root wheel 512 Dec 21 10:19 cdrom 444 lrwxr-xr-x 1 root wheel 11 Dec 21 12:27 compat -> /usr/compat 6272 drwxr-xr-x 3 root wheel 13824 Feb 25 09:15 dev 36 drwxr-xr-x 15 root wheel 2048 Dec 22 18:20 etc 236 drwxr-xr-x 1 root wheel 7168 Jan 1 1980 floppy 451 lrwxrwxrwx 1 root wheel 9 Dec 21 12:29 home -> /usr/home 443 -r-xr-xr-x 1 root wheel 3258128 Nov 20 08:02 kernel 442 -r-xr-xr-x 1 root wheel 3258128 Nov 20 08:02 kernel.GENERIC 241 drwxr-xr-x 2 root wheel 512 Nov 20 06:56 mnt 242 drwxr-xr-x 2 root wheel 2560 Dec 21 10:33 modules 2 dr-xr-xr-x 1 root wheel 512 Feb 25 10:32 proc 358 drwxr-xr-x 2 root wheel 512 Dec 23 08:30 root 363 drwxr-xr-x 2 root wheel 2048 Dec 21 19:09 sbin 5 drwxr-xr-x 4 root wheel 1024 Dec 21 10:19 stand 440 lrwxrwxrwx 1 root wheel 11 Dec 21 12:22 sys -> usr/src/sys 2 drwxrwxrwt 2 root wheel 512 Feb 25 09:15 tmp 2 drwxr-xr-x 19 root wheel 512 Feb 11 19:04 usr 2 drwxr-xr-x 18 root wheel 512 Nov 20 08:13 var
Notice that this output added an extra column to the long listing; the number in the first column is the inode number for that file. Inode number "2" has been mentioned four times; once for proc, tmp, usr, and var. Inode 2 is always the first inode of a filesystem and represents the root or starting point of that filesystem. We can use the df command to see which filesystems have been mounted on this system:
df Filesystem 1K-blocks Used Avail Capacity Mounted on /dev/ad0s2a 49583 27729 17888 61% / /dev/ad0s2f 2967289 737169 1992737 27% /usr /dev/ad0s2e 19815 3647 14583 20% /var procfs 4 4 0 100% /proc mfs:27 131231 1 120732 0% /tmp
Not surprisingly, usr, var, proc and tmp show up as mounted filesystems. Don't forget that each filesystem maintains its own inode table; that is, inode 2 for usr is a different inode entry in a completely different inode table than the inode 2 entry for "var." The only thing these inode entries share in common is the number 2, as they are both the root entry for their respective filesystems.
The df or disk free utility has a switch that will tell you how many inodes are on each filesystem. Let's run the df utility again with the i switch. View the output:
df -i Filesystem 1K-blocks Used Avail Capacity iused ifree %iused Mounted on /dev/ad0s2a 49583 27729 17888 61% 1074 11468 9% / /dev/ad0s2f 2967289 739993 1989913 27% 90852 655130 12% /usr /dev/ad0s2e 19815 3645 14585 20% 391 4663 8% /var procfs 4 4 0 100% 25 507 5% /proc mfs:27 131231 1 120732 0% 1 33277 0% /tmp
It's a good idea to run this command on a regular basis to ensure that your filesystems are not running out of either disk storage blocks or inode entries. Unless you are creating a large number of very small files, you will probably run out of disk blocks long before you run out of inodes. Knowing whether or not you've created enough inodes while leaving enough storage blocks is a matter of experience, as it depends upon what your FreeBSD system is used for and what types of files are created by your users. If you run this command often, you'll get an idea of what is normal for your system; you'll also learn if the defaults are not appropriate for your system.
The last thing I'd like you to notice about an inode is that it keeps track of three different times: the file's mtime, atime, and ctime.
A file's "mtime" is its last modification time; that is, when the actual contents of the file were last changed. For example, if you open a file with your favourite text editor and add or delete some text, you have modified the contents of that file. When you save your changes, the inode will update the "mtime" of that file. Remember that ls -l will show the mtime of the file.
A file's "atime" is the last time that file was accessed. For example, if you read a file using a pager, you will access the file and the inode will update the "atime" for that file. You can view a directory listing by atime instead of the default mtime by using the switches lut as shown:
ls -lut / total 6429 dr-xr-xr-x 1 root wheel 512 Feb 26 14:06 proc drwxr-xr-x 2 root wheel 1024 Feb 26 14:03 bin drwxr-xr-x 2 root wheel 2048 Feb 26 14:03 sbin drwxr-xr-x 3 root wheel 13824 Feb 26 13:54 dev drwxrwxrwt 2 root wheel 512 Feb 26 13:54 tmp drwxr-xr-x 19 root wheel 512 Feb 25 14:02 usr drwxr-xr-x 18 root wheel 512 Feb 20 02:01 var drwxr-xr-x 2 root wheel 512 Feb 20 01:59 root drwxr-xr-x 4 root wheel 1024 Feb 20 01:59 stand drwxr-xr-x 15 root wheel 2048 Feb 20 01:59 etc drwxr-xr-x 2 root wheel 512 Feb 20 01:59 cdrom drwxr-xr-x 3 root wheel 512 Feb 20 01:59 boot drwxr-xr-x 2 root wheel 512 Feb 20 01:59 mnt drwxr-xr-x 2 root wheel 2560 Feb 20 01:59 modules lrwxrwxrwx 1 root wheel 9 Dec 21 12:29 home -> /usr/home lrwxr-xr-x 1 root wheel 11 Dec 21 12:27 compat -> /usr/compat lrwxrwxrwx 1 root wheel 11 Dec 21 12:22 sys -> usr/src/sys -r-xr-xr-x 1 root wheel 3258128 Nov 20 08:02 kernel -r-xr-xr-x 1 root wheel 3258128 Nov 20 08:02 kernel.GENERIC -r--r--r-- 1 root wheel 4735 Nov 20 07:03 COPYRIGHT drwxr-xr-x 1 root wheel 7168 Jan 1 1980 floppy
The "ctime" is updated whenever the inode itself is changed. For example, if you change the permissions, owner, or group of a file you are actually making changes to that file's inode, so the "ctime" will also be updated. To see a listing by ctime, use the switches lc with the ls utility, as shown:
ls -lc / total 6429 -r--r--r-- 1 root wheel 4735 Dec 21 12:22 COPYRIGHT drwxr-xr-x 2 root wheel 1024 Dec 21 19:09 bin drwxr-xr-x 3 root wheel 512 Dec 21 12:27 boot drwxr-xr-x 2 root wheel 512 Dec 21 10:19 cdrom lrwxr-xr-x 1 root wheel 11 Dec 21 12:27 compat -> /usr/compat drwxr-xr-x 3 root wheel 13824 Feb 26 13:54 dev drwxr-xr-x 15 root wheel 2048 Dec 22 18:20 etc drwxr-xr-x 1 root wheel 7168 Jan 1 1980 floppy lrwxrwxrwx 1 root wheel 9 Dec 21 12:29 home -> /usr/home -r-xr-xr-x 1 root wheel 3258128 Dec 21 12:27 kernel -r-xr-xr-x 1 root wheel 3258128 Feb 11 19:04 kernel.GENERIC drwxr-xr-x 2 root wheel 512 Dec 21 10:27 mnt drwxr-xr-x 2 root wheel 2560 Dec 21 10:33 modules dr-xr-xr-x 1 root wheel 512 Feb 26 14:07 proc drwxr-xr-x 2 root wheel 512 Dec 23 08:30 root drwxr-xr-x 2 root wheel 2048 Dec 21 19:09 sbin drwxr-xr-x 4 root wheel 1024 Dec 21 10:19 stand lrwxrwxrwx 1 root wheel 11 Dec 21 12:22 sys -> usr/src/sys drwxrwxrwt 2 root wheel 512 Feb 26 13:54 tmp drwxr-xr-x 19 root wheel 512 Feb 11 19:04 usr drwxr-xr-x 18 root wheel 512 Dec 21 19:15 var
If you take a close look at those last three ls listings, you'll note that the times are indeed different and reflect the three types of times recorded by each file's inode.
Next week, I'd like to start taking a closer look at IP packets and headers so you'll have the grounding necessary to understand packet filters and firewalls.
Read more from FreeBSD Basics.