V irtual Why add layers? Core Data Structures Only Exist Originally, operating systems supported just F ile system In Memory everything a process requires to file one file system. What changed? interact with an open file ● introduction of removable media (floppy, CD-ROM, usb S witch dentry created for every component of a drives, etc.) pathname - a speicalized cache to ● demand for network file systems (nfs, cifs, etc.) aid in lookup Design decisions ● Dedicated libraries for each file system type? Mirrored all information needed by a file inode ○ hard on application programmers system to handle a file A brief overview of the Linux storage On Disk ● What about common operations, like path lookup? ○ a shared layer between application and FS allows stack data pertaining to a mounted file superblock for code reuse system Impact on Designing a FS File Operations Inode Operations adjust file ● Designers define a subset of common struct file_operations { struct inode_operations { loff_t (*llseek) (struct file *, loff_t, int); position int (*create) (struct inode *,struct dentry *,int, struct nameidata *); read from disk ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *); functions ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); int (*link) (struct dentry *,struct inode *,struct dentry *); ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); read/write data int (*unlink) (struct inode *,struct dentry *); ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); int (*symlink) (struct inode *,struct dentry *,const char *); manage links ○ register each file system with the kernel int (*readdir) (struct file *, void *, filldir_t); int (*mkdir) (struct inode *,struct dentry *,int); unsigned int (*poll) (struct file *, struct poll_table_struct *); int (*rmdir) (struct inode *,struct dentry *); ○ when a file system is mounted, the kernel finds its int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); int (*mknod) (struct inode *,struct dentry *,int,dev_t); long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); int (*rename) (struct inode *, struct dentry *, functions in the table of registered file systems long (*compat_ioctl) (struct file *, unsigned int, unsigned long); struct inode *, struct dentry *); map to memory int (*mmap) (struct file *, struct vm_area_struct *); int (*readlink) (struct dentry *, char __user *,int); check int (*open) (struct inode *, struct file *); void * (*follow_link) (struct dentry *, struct nameidata *); permissions int (*flush) (struct file *, fl_owner_t id); void (*put_link) (struct dentry *, struct nameidata *, void *); int (*release) (struct inode *, struct file *); int (*permission) (struct inode *, int); ● VFS calls FS functions at known locations int (*fsync) (struct file *, int datasync); int (*check_acl)(struct inode *, int); int (*aio_fsync) (struct kiocb *, int datasync); int (*setattr) (struct dentry *, struct iattr *); sync to disk int (*fasync) (int, struct file *, int); int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *); int (*lock) (struct file *, int, struct file_lock *); int (*setxattr) (struct dentry *, const char *,const void *,size_t,int); ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t); manage blocks Question: How much flexibility unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); ssize_t (*listxattr) (struct dentry *, char *, size_t); int (*check_flags)(int); int (*removexattr) (struct dentry *, const char *); int (*flock) (struct file *, int, struct file_lock *); void (*truncate) (struct inode *); does the VFS give us? ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); void (*truncate_range)(struct inode *, loff_t, loff_t); ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); long (*fallocate)(struct inode *inode, int mode, loff_t offset, int (*setlease)(struct file *, long, struct file_lock **); loff_t len); }; int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len); }
Super Operations Dentry Operations Interacting with the VFS struct super_operations { struct dentry_operations { ● Root file system mounted at ' / ' and defines a struct inode *(*alloc_inode)(struct super_block *sb); int (*d_revalidate)(struct dentry *, struct nameidata *); void (*destroy_inode)(struct inode *); int (*d_hash) (struct dentry *, struct qstr *); generally use generic hash void (*dirty_inode) (struct inode *); create/destroy/commit int (*d_compare) (struct dentry *, struct qstr *, struct qstr *); tree function int (*write_inode) (struct inode *, struct writeback_control *wbc); inodes int (*d_delete)(struct dentry *); void (*drop_inode) (struct inode *); void (*d_release)(struct dentry *); hooks called before ● Additional file systems can be mounted over void (*delete_inode) (struct inode *); void (*d_iput)(struct dentry *, struct inode *); deleting/freeing void (*put_super) (struct super_block *); char *(*d_dname)(struct dentry *, char *, int); void (*write_super) (struct super_block *); }; existing directories, filling out the tree int (*sync_fs)(struct super_block *sb, int wait); synchronize file system inode and dentry caches coupled int (*freeze_fs) (struct super_block *); state int (*unfreeze_fs) (struct super_block *); ● System calls like open(2) that take a name int (*remount_fs) (struct super_block *, int *, char *); void (*clear_inode) (struct inode *); summarize file system as input perform pathname lookup void (*umount_begin) (struct super_block *); state int (*statfs) (struct dentry *, struct kstatfs *); int (*show_options)(struct seq_file *, struct vfsmount *); “ dcache ” is just a hashtable int (*show_stats)(struct seq_file *, struct vfsmount *); ○ Pathname lookup can start at ' / ' or in the current #ifdef CONFIG_QUOTA ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t); working directory ( cwd specified in process desc.) ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t); #endif int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t); ○ Performs permission checks, creates struct }; dentry s, reads on-disk inodes and instantiates in- memory struct inode s Example (pathname lookup) Example (pathname lookup) Example (pathname lookup) int fd = open("/home/bill/foo.txt", O_RDWR); int fd = open("/home/bill/foo.txt", O_RDWR); int fd = open("/home/bill/foo.txt", O_RDWR); ● The filename starts wtih a ' / ' ● check the exec permission of the inode for ' / ' ● now look to see if a dentry for ' home ' exists in hashtable ○ consult the process descriptor to find the root dentry ○ inode->i_op->permission(inode, MAY_EXEC); ○ dentry = d_lookup(parent_dentry, "home") ++refcounts on both the Each dentry points to a Each inode has an i_op "home" dentry and its corresponding inode , field, which stores the set of fs_struct files ● It exists in our dcache! which we need to continue file system specific inode corresponding { ○ we don't need to go to disk to look up the inode our traversal functions dentry->d_inode ... task_struct current { dentry root ... dentry pwd fs_struct fs } files_struct files ... I: / I: / I: home I: / } D: / D: / D: home D: / dcache: dcache: dcache:
Recommend
More recommend