Understanding the Linux inodes
Linux makes a clear distinction between the contents of a file and the information about a file. All information needed by the filesystem to handle a file is included in a data structure called an inode. Each file has its own inode, which the filesystem uses to identify the file.
File types
Linux files may be one of the following types.
- Regular file
- Directory
- Symbolic link
- Block device file
- Character device file
- Pipe(FIFO)
- Socket
The first three file types are constituents of any Linux filesystem. Device files are related both to I/O devices, and to device drivers integrated into the kernel. When a program accesses a device file, it acts directly on the I/O device associated with that file. Pipes and sockets are special files used for interprocess communication.
File inodes
Linux system must provide the following inode attributes, which are specified in the POSIX standard:
- File type
- Link count: Number of hard links associated with the file
- File size in bytes
- Device ID(i.e., the identifier of the device containing the file)
- Inode number that identifies the file in the filesystem
- UID of the file owner
- User group ID of the file
- Timestamps which specify the inode change time, the last access time and the last modify time.
- Access rights/permissions(read, write, and execute) and file mode
The following is inode struct definition in the Linux source code.
/*
* Keep mostly read-only and often accessed (especially for
* the RCU path lookup and 'stat' data) fields at the beginning
* of the 'struct inode'
*/
struct inode {
umode_t i_mode;
unsigned short i_opflags;
kuid_t i_uid;
kgid_t i_gid;
unsigned int i_flags;
#ifdef CONFIG_FS_POSIX_ACL
struct posix_acl *i_acl;
struct posix_acl *i_default_acl;
#endif
const struct inode_operations *i_op;
struct super_block *i_sb;
struct address_space *i_mapping;
#ifdef CONFIG_SECURITY
void *i_security;
#endif
/* Stat data, not accessed from path walking */
unsigned long i_ino;
/*
* Filesystems may only read i_nlink directly. They shall use the
* following functions for modification:
*
* (set|clear|inc|drop)_nlink
* inode_(inc|dec)_link_count
*/
union {
const unsigned int i_nlink;
unsigned int __i_nlink;
};
dev_t i_rdev;
loff_t i_size;
struct timespec64 i_atime;
struct timespec64 i_mtime;
struct timespec64 i_ctime;
spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */
unsigned short i_bytes;
u8 i_blkbits;
u8 i_write_hint;
blkcnt_t i_blocks;
#ifdef __NEED_I_SIZE_ORDERED
seqcount_t i_size_seqcount;
#endif
/* Misc */
unsigned long i_state;
struct rw_semaphore i_rwsem;
unsigned long dirtied_when; /* jiffies of first dirtying */
unsigned long dirtied_time_when;
struct hlist_node i_hash;
struct list_head i_io_list; /* backing dev IO list */
#ifdef CONFIG_CGROUP_WRITEBACK
struct bdi_writeback *i_wb; /* the associated cgroup wb */
/* foreign inode detection, see wbc_detach_inode() */
int i_wb_frn_winner;
u16 i_wb_frn_avg_time;
u16 i_wb_frn_history;
#endif
struct list_head i_lru; /* inode LRU list */
struct list_head i_sb_list;
struct list_head i_wb_list; /* backing dev writeback list */
union {
struct hlist_head i_dentry;
struct rcu_head i_rcu;
};
atomic64_t i_version;
atomic64_t i_sequence; /* see futex */
atomic_t i_count;
atomic_t i_dio_count;
atomic_t i_writecount;
#if defined(CONFIG_IMA) || defined(CONFIG_FILE_LOCKING)
atomic_t i_readcount; /* struct files open RO */
#endif
union {
const struct file_operations *i_fop; /* former ->i_op->default_file_ops */
void (*free_inode)(struct inode *);
};
struct file_lock_context *i_flctx;
struct address_space i_data;
struct list_head i_devices;
union {
struct pipe_inode_info *i_pipe;
struct cdev *i_cdev;
char *i_link;
unsigned i_dir_seq;
};
__u32 i_generation;
#ifdef CONFIG_FSNOTIFY
__u32 i_fsnotify_mask; /* all events this inode cares about */
struct fsnotify_mark_connector __rcu *i_fsnotify_marks;
#endif
#ifdef CONFIG_FS_ENCRYPTION
struct fscrypt_info *i_crypt_info;
#endif
#ifdef CONFIG_FS_VERITY
struct fsverity_info *i_verity_info;
#endif
void *i_private; /* fs or device private pointer */
} __randomize_layout;
Display inode information
The inode data can be displayed with the stat command.
$ echo "hello inode" > testfile
$ debugfs /dev/mapper/vgroot-lvroot
debugfs 1.42.9 (28-Dec-2013)
debugfs: q
[root@init500-d1 ~]# stat testfile
File: ‘testfile’
Size: 12 Blocks: 8 IO Block: 4096 regular file
Device: fd00h/64768d Inode: 27787306 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2022-04-30 20:40:38.496696650 +0000
Modify: 2022-04-30 20:40:38.496696650 +0000
Change: 2022-04-30 20:40:38.496696650 +0000
Birth: -
$ stat --format=%i testfile
27787306
The inode number can be also displayed with ls -i command. With ls -l command, it displays file permissions for the owner, group and others. In the following example, the owner has read and write permission. The group and others only have read permission.
$ ls -il testfile
27787306 -rw-r--r-- 1 root root 12 Apr 30 20:40 testfile
The inode space information can be displayed with df -i command.
$ df -i
Filesystem Inodes IUsed IFree IUse% Mounted on
devtmpfs 132058034 953 132057081 1% /dev
tmpfs 132061520 4 132061516 1% /dev/shm
tmpfs 132061520 1270 132060250 1% /run
tmpfs 132061520 17 132061503 1% /sys/fs/cgroup
/dev/mapper/vgroot-lvroot 97320960 188567 97132393 1% /
/dev/nvme0n1p2 128016 31 127985 1% /boot
/dev/nvme0n1p1 0 0 0 - /boot/efi
tmpfs 132061520 1 132061519 1% /run/user/0
tmpfs 132061520 1 132061519 1% /var/lib/osd/lttng
The content of filesystem superblock can be listed with tune2fs command. The inode related information can be grepped.
$ tune2fs -l /dev/mapper/vgroot-lvroot | grep -i inode
Filesystem features: has_journal ext_attr resize_inode dir_index filetype needs_recovery extent 64bit flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize
Inode count: 97320960
Free inodes: 97167388
Inodes per group: 8192
Inode blocks per group: 512
First inode: 11
Inode size: 256
Journal inode: 8
First orphan inode: 22157990
Journal backup: inode blocks
The debugfs program is an interactive file system debugger. It can be used to examine and change the state of an ext2, ext3, or ext4 file system.
$ debugfs /dev/mapper/vgroot-lvroot
debugfs 1.42.9 (28-Dec-2013)
debugfs: stat <27787306>
Inode: 27787306 Type: regular Mode: 0644 Flags: 0x80000
Generation: 269876152 Version: 0x00000000:00000001
User: 0 Group: 0 Size: 12
File ACL: 0 Directory ACL: 0
Links: 1 Blockcount: 8
Fragment: Address: 0 Number: 0 Size: 0
ctime: 0x626d9ec6:766bf528 -- Sat Apr 30 20:40:38 2022
atime: 0x626d9ec6:766bf528 -- Sat Apr 30 20:40:38 2022
mtime: 0x626d9ec6:766bf528 -- Sat Apr 30 20:40:38 2022
crtime: 0x626d9ec6:766bf528 -- Sat Apr 30 20:40:38 2022
Size of extra inode fields: 32
EXTENTS:
(0):111182849
Inode structure for the directory can be displayed as below.
$ stat /
File: ‘/’
Size: 4096 Blocks: 8 IO Block: 4096 directory
Device: fd00h/64768d Inode: 2 Links: 18
Access: (0555/dr-xr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2022-04-14 23:50:13.812053511 +0000
Modify: 2022-04-30 20:42:56.468650708 +0000
Change: 2022-04-30 20:42:56.468650708 +0000
Birth: -