2021SC@SDUSC
Inode
While superblocks stand for each file systems,Inodes stand for every file and each file has an inode which include all information for kernal to operate those files.Be aware that even every file being used has an inode block to operate, it will only be created while the file ever accessed.Only if a file being accessed will an inode been created in RAM.
So it's more like an inode is not a file but some 'basic-data' for operating the file, such as the call link() which aims to create a hard link of the file old_dentry in the directory dir with the new filename dentry is related to inode structure.If you have a glance at fs.h, you'll see huge number of functions needs such inode to be done.
The structure of inode is also in fs.h, that is:
struct inode {
umode_t i_mode;
unsigned short i_opflags;
kuid_t i_uid;
kgid_t i_gid;
unsigned int i_flags;
struct posix_acl *i_acl;
struct posix_acl *i_default_acl;
const struct inode_operations *i_op;
struct super_block *i_sb;
struct address_space *i_mapping;
void *i_security;
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;
/* 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 */
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;
inode had provided necessary pointers and status for user and kernal to use for call.Some of the status might not be suitable for all file systems and it's not necessary for them, so the file system could realize their own function to fill these status.
For some special file, pointers were made in this union space:
union {
struct pipe_inode_info *i_pipe;
struct cdev *i_cdev;
char *i_link;
unsigned i_dir_seq;
};
while i_pipe point at pipe structure, i_cdev point at charactor device.One file is either one of these spcial files or not, so they are blocked in an union space all together.
Functions for inode
In inode structure shown above, i_op point at function list for inodes just like s_op and superblock_operations.inode_operations is also stored in fs.h
struct inode_operations {
struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
const char * (*get_link) (struct dentry *, struct inode *, struct delayed_call *);
int (*permission) (struct user_namespace *, struct inode *, int);
struct posix_acl * (*get_acl)(struct inode *, int);
int (*readlink) (struct dentry *, char __user *,int);
int (*create) (struct user_namespace *, struct inode *,struct dentry *,
umode_t, bool);
int (*link) (struct dentry *,struct inode *,struct dentry *);
int (*unlink) (struct inode *,struct dentry *);
int (*symlink) (struct user_namespace *, struct inode *,struct dentry *,
const char *);
int (*mkdir) (struct user_namespace *, struct inode *,struct dentry *,
umode_t);
int (*rmdir) (struct inode *,struct dentry *);
int (*mknod) (struct user_namespace *, struct inode *,struct dentry *,
umode_t,dev_t);
int (*rename) (struct user_namespace *, struct inode *, struct dentry *,
struct inode *, struct dentry *, unsigned int);
int (*setattr) (struct user_namespace *, struct dentry *,
struct iattr *);
int (*getattr) (struct user_namespace *, const struct path *,
struct kstat *, u32, unsigned int);
ssize_t (*listxattr) (struct dentry *, char *, size_t);
int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
u64 len);
int (*update_time)(struct inode *, struct timespec64 *, int);
int (*atomic_open)(struct inode *, struct dentry *,
struct file *, unsigned open_flag,
umode_t create_mode);
int (*tmpfile) (struct user_namespace *, struct inode *,
struct dentry *, umode_t);
int (*set_acl)(struct user_namespace *, struct inode *,
struct posix_acl *, int);
int (*fileattr_set)(struct user_namespace *mnt_userns,
struct dentry *dentry, struct fileattr *fa);
int (*fileattr_get)(struct dentry *dentry, struct fileattr *fa);
} ____cacheline_aligned;
These functions are to operate inode.Some of the methods are shown as below.
int create(struct inode *dir, struct dentry *dentry, int mode)
The VFS calls this function from the creat() and open() system calls to create a new inode associated with the given dentry object with the specified initial access mode.
What means exactly associated with the given dentry?Dentries are the elements we can see in each folder, which could not only be files but also indexed and devices(remember that everying in linux are files.)
About dentry, we will talk about that later.
struct dentry* lookup(struct inode *dir, struct dentry *dentry)
This function searches a directory for an inode corresponding to a filename specified in the given dentry.
int link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
Invoked by the link() system call to create a hard link of the file old_dentry in the directory dir with the new filename dentry.
int unlink(struct inode *dir, struct dentry *dentry)
Called from the unlink() system call to remove the inode specified by the directory entry dentry from the directory dir.
link and unlink function create a hard-link from one dentry to another, so we can see that a link are based on inodes.
int follow_link(struct dentry *dentry, struct nameidata *nd)
Called by the VFS to translate a symbolic link to the inode to which it points.
int permission(struct inode *inode, int mask)
Checks whether the specified access mode is allowed for the file referenced by inode
An inode is actually the bridge for VFS to operate a lot of operations such as create a hard-like for directory entry(dentry), so we shall talk about directory that users can access right after inodes.
Directory Entry(Dentry)
Dentry is certain elements in file index.To start with, I have to talk about a discussion with my crew.
Mr. Han and I are in the same group, and he is analyzing the code for ext2 and ext4 file system, that is one of the important part in our linux kernal project, and it's basically used in linux.We were studying different headers, but the conclusion we made were quite same.The superblocks for each fs and devices and inode for each file not only appear in fs.h in linux folder but also in ext2 folder.All these appearence caused something in our mind that VFS is actually transfer other filesystems such as fat32(which does not have real inode structure because files are list-like stored) into ext2.It does't mean they are really changed, but VFS are taking data from other fs and expose to kernal in an ext-like way.
Is that true?I hope we'll find out later.
Anyway, a dentry is an element in certain route.Such as include/linux/a.txt has 3 dentry that is linux,a.txt,and /.Structure for dentry are defined in dcache.h.What is that cache stand for?
struct dentry {
/* RCU lookup touched fields */
unsigned int d_flags; /* protected by d_lock */
seqcount_spinlock_t d_seq; /* per dentry seqlock */
struct hlist_bl_node d_hash; /* lookup hash list */
struct dentry *d_parent; /* parent directory */
struct qstr d_name;
struct inode *d_inode; /* Where the name belongs to - NULL is
* negative */
unsigned char d_iname[DNAME_INLINE_LEN]; /* small names */
/* Ref lookup also touches following */
struct lockref d_lockref; /* per-dentry lock and refcount */
const struct dentry_operations *d_op;
struct super_block *d_sb; /* The root of the dentry tree */
unsigned long d_time; /* used by d_revalidate */
void *d_fsdata; /* fs-specific data */
union {
struct list_head d_lru; /* LRU list */
wait_queue_head_t *d_wait; /* in-lookup ones only */
};
struct list_head d_child; /* child of parent list */
struct list_head d_subdirs; /* our children */
/*
* d_alias and d_rcu can share memory
*/
union {
struct hlist_node d_alias; /* inode alias list */
struct hlist_bl_node d_in_lookup_hash; /* only for in-lookup ones */
struct rcu_head d_rcu;
} d_u;
} __randomize_layout;
A dentry is usually associated to a inode, but sometimes the inode has been removed but dentry still exsited in dentry cache.And we also notice there is a RCU loopup.We may talk about that later.