Team LiB
Previous Section Next Section

The Inode Object

The inode object represents all the information needed by the kernel to manipulate a file or directory. For Unix-style filesystems, this information is simply read from the on-disk inode. If a filesystem does not have inodes, however, the filesystem must obtain the information from wherever it is stored on the disk[4].

[4] Filesystems without inodes generally store the information as part of the file itself. Some modern filesystems also employ a database to store the file's data. Whatever the case, the inode object is constructed in whatever manner is applicable to the filesystem.

The inode object is represented by struct inode and is defined in <linux/fs.h>. Here is the structure, with comments describing each entry:

struct inode {
        struct hlist_node       i_hash;              /* hash list */
        struct list_head        i_list;              /* list of inodes */
        struct list_head        i_dentry;            /* list of dentries */
        unsigned long           i_ino;               /* inode number */
        atomic_t                i_count;             /* reference counter */
        umode_t                 i_mode;              /* access permissions */
        unsigned int            i_nlink;             /* number of hard links */
        uid_t                   i_uid;               /* user id of owner */
        gid_t                   i_gid;               /* group id of owner */
        kdev_t                  i_rdev;              /* real device node */
        loff_t                  i_size;              /* file size in bytes */
        struct timespec         i_atime;             /* last access time */
        struct timespec         i_mtime;             /* last modify time */
        struct timespec         i_ctime;             /* last change time */
        unsigned int            i_blkbits;           /* block size in bits */
        unsigned long           i_blksize;           /* block size in bytes */
        unsigned long           i_version;           /* version number */
        unsigned long           i_blocks;            /* file size in blocks */
        unsigned short          i_bytes;             /* bytes consumed */
        spinlock_t              i_lock;              /* spinlock */
        struct rw_semaphore     i_alloc_sem;         /* nests inside of i_sem */
        struct semaphore        i_sem;               /* inode semaphore */
        struct inode_operations *i_op;               /* inode ops table */
        struct file_operations  *i_fop;              /* default inode ops */
        struct super_block      *i_sb;               /* associated superblock */
        struct file_lock        *i_flock;            /* file lock list */
        struct address_space    *i_mapping;          /* associated mapping */
        struct address_space    i_data;              /* mapping for device */
        struct dquot            *i_dquot[MAXQUOTAS]; /* disk quotas for inode */
        struct list_head        i_devices;           /* list of block devices */
        struct pipe_inode_info  *i_pipe;             /* pipe information */
        struct block_device     *i_bdev;             /* block device driver */
        unsigned long           i_dnotify_mask;      /* directory notify mask */
        struct dnotify_struct   *i_dnotify;          /* dnotify */
        unsigned long           i_state;             /* state flags */
        unsigned long           dirtied_when;        /* first dirtying time */
        unsigned int            i_flags;             /* filesystem flags */
        unsigned char           i_sock;              /* is this a socket? */
        atomic_t                i_writecount;        /* count of writers */
        void                    *i_security;         /* security module */
        __u32                   i_generation;        /* inode version number */
        union {
                void            *generic_ip;         /* filesystem-specific info */
        } u;
};

An inode represents each file on a filesystem (although an inode object is constructed in memory only as the files are accessed). This includes special files, such as device files or pipes. Consequently, some of the entries in struct inode are related to these special files. For example, the i_pipe enTRy points to a named pipe data structure. If the inode does not refer to a named pipe, this field is simply NULL. Other special file-related fields are i_devices, i_bdev, and i_cdev.

It might occur that a given filesystem does not support a property represented in the inode object. For example, some filesystems might not record an access timestamp. In that case, the filesystem is free to implement the feature however it sees fit; it can store zero for i_atime, make i_atime equal to i_mtime, or whatever floats its boat.

Inode Operations

As with the superblock operations, the inode_operations member is very important. It describes the filesystem's implemented functions that the VFS can invoke on an inode. As with the superblock, inode operations are invoked via

i->i_op->truncate(i)

where i is a reference to a particular inode. In this case, the truncate() operation defined by the filesystem on which i exists is called on the given inode. The inode_operations structure is defined in <linux/fs.h>:

struct inode_operations {
        int (*create) (struct inode *, struct dentry *,int);
        struct dentry * (*lookup) (struct inode *, struct dentry *);
        int (*link) (struct dentry *, struct inode *, struct dentry *);
        int (*unlink) (struct inode *, struct dentry *);
        int (*symlink) (struct inode *, struct dentry *, const char *);
        int (*mkdir) (struct inode *, struct dentry *, int);
        int (*rmdir) (struct inode *, struct dentry *);
        int (*mknod) (struct inode *, struct dentry *, int, dev_t);
        int (*rename) (struct inode *, struct dentry *,
                       struct inode *, struct dentry *);
        int (*readlink) (struct dentry *, char *, int);
        int (*follow_link) (struct dentry *, struct nameidata *);
        int (*put_link) (struct dentry *, struct nameidata *);
        void (*truncate) (struct inode *);
        int (*permission) (struct inode *, int);
        int (*setattr) (struct dentry *, struct iattr *);
        int (*getattr) (struct vfsmount *, struct dentry *, struct kstat *);
        int (*setxattr) (struct dentry *, const char *,
                         const void *, size_t, int);
        ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
        ssize_t (*listxattr) (struct dentry *, char *, size_t);
        int (*removexattr) (struct dentry *, const char *);
};

The following interfaces constitute the various functions that the VFS may perform, or ask a specific filesystem to perform, on a given inode:

  • 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 mode.

  • 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)
    

    The function is 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)
    

    This function is called from the unlink() system call to remove the inode specified by the directory entry dentry from the directory dir.

  • int symlink(struct inode *dir,
                 struct dentry *dentry,
                 const char *symname)
    

    This function is called from the symlink() system call to create a symbolic link named symname to the file represented by dentry in the directory dir.

  • int mkdir(struct inode *dir,
               struct dentry *dentry, int mode)
    

    This function is called from the mkdir() system call to create a new directory with the given initial mode.

  • int rmdir(struct inode *dir,
               struct dentry *dentry)
    

    This function is called by the rmdir() system call to remove the directory referenced by dentry from the directory dir.

  • int mknod(struct inode *dir,
               struct dentry *dentry,
               int mode, dev_t rdev)
    

    This function is called by the mknod() system call to create a special file (device file, named pipe, or socket). The file is referenced by the device rdev and the directory entry dentry in the directory dir. The initial permissions are given via mode.

  • int rename(struct inode *old_dir,
                struct dentry *old_dentry,
                struct inode *new_dir,
                struct dentry *new_dentry)
    

    This function is called by the VFS to move the file specified by old_dentry from the old_dir directory to the directory new_dir, with the filename specified by new_dentry.

  • int readlink(struct dentry *dentry,
                  char *buffer, int buflen)
    

    This function is called by the readlink() system call to copy at most buflen bytes of the full path associated with the symbolic link specified by dentry into the specified buffer.

  • int follow_link(struct dentry *dentry,
                     struct nameidata *nd)
    

    This function is called by the VFS to translate a symbolic link to the inode to which it points. The link pointed at by dentry is translated and the result is stored in the nameidata structure pointed at by nd.

  • int put_link(struct dentry *dentry,
                  struct nameidata *nd)
    

    This function is called by the VFS to clean up after a call to follow_link().

  • void truncate(struct inode *inode)

    This function is called by the VFS to modify the size of the given file. Before invocation, the inode's i_size field must be set to the desired new size.

  • int permission(struct inode *inode, int mask)

    This function checks whether the specified access mode is allowed for the file referenced by inode. This function returns zero if the access is allowed and a negative error code otherwise. Most filesystems set this field to NULL and use the generic VFS method, which simply compares the mode bits in the inode's objects to the given mask. More complicated filesystems, such as those supporting access control lists (ACLs), have a specific permission() method.

  • int setattr(struct dentry *dentry,
                 struct iattr *attr)
    

    This function is called from notify_change() to notify a "change event" after an inode has been modified.

  • int getattr(struct vfsmount *mnt,
                 struct dentry *dentry,
                 struct kstat *stat)
    

    This function is invoked by the VFS upon noticing that an inode needs to be refreshed from disk.

  • int setxattr(struct dentry *dentry,
                  const char *name,
                  const void *value, size_t size,
                  int flags)
    

    This function is used by the VFS to set the extended attribute[5] name to the value value on the file referenced by dentry.

    [5] Extended attributes are a new feature introduced in the 2.6 kernel for pairing key/value pairs to files, similar to a database. They allow the association of user-specified arbitrary metadata and files.

  • ssize_t getxattr(struct dentry *dentry,
                      const char *name,
                      void *value, size_t size) 
    

    This function is used by the VFS to copy into value the value of the extended attribute name for the specified file.

  • ssize_t listxattr(struct dentry *dentry,
                       char *list, size_t size)
    

    This function copies the list of all attributes for the specified file into the buffer list.

  • int removexattr(struct dentry *dentry,
                     const char *name)
    

    This function removes the given attribute from the given file.

    Team LiB
    Previous Section Next Section