<--inodes ^--VFS--^ dentries-->

How to write a Linux VFS filesystem module - files

March 5, 2004


Files, from the VFS's view, are records that detail interaction with a filesystem object. Things like the pointer into the file, lookahead information, and most importantly, a structure containing more function pointers to tell VFS how to access files in your file system, are part of the file structure. This structure can be seen in /usr/src/linux/include/linux/fs.h as struct file. The structure that we populate as VFS module writers is a struct file_operations, shown here:
struct file_operations {
        struct module *owner;
        loff_t (*llseek) (struct file *, loff_t, int);
        ssize_t (*read) (struct file *, char *, size_t, loff_t *);
        ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
        int (*readdir) (struct file *, void *, filldir_t);
        unsigned int (*poll) (struct file *, struct poll_table_struct *);
        int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
        int (*mmap) (struct file *, struct vm_area_struct *);
        int (*open) (struct inode *, struct file *);
        int (*flush) (struct file *);
        int (*release) (struct inode *, struct file *);
        int (*fsync) (struct file *, struct dentry *, int datasync);
        int (*fasync) (int, struct file *, int);
        int (*lock) (struct file *, int, struct file_lock *);
        ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
        ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
        ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
        unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
and here is the structure in ramfs:
static struct file_operations ramfs_file_operations = {
        read:           generic_file_read,
        write:          generic_file_write,
        mmap:           generic_file_mmap,
        fsync:          ramfs_sync_file,
This structure was supplied to VFS within the inode structures, when we created inodes in our ramfs_get_inode() function. Again we see a lot of functions not being implemented, which must mean that VFS has a default way of handling events which works for the most part for other filesystems (or, at least ramfs).

Also, of the four that are supplied, three of them, the generic_file_*() ones, aren't supplied by the module. But if they're being explicitly put into the structure, does that mean that these aren't the default ones that VFS uses if none are supplied? Or was the author just being explicit? I'll have to take a look at that later.

The one that is written locally is ramfs_sync_file():

static int ramfs_sync_file(struct file * file, struct dentry *dentry, int datasync)
        return 0;
The fsync function is for activating or deactivating asynchronous I/O notification. It looks like ramfs ignores this. And that's about it for the struct file, in ramfs, at least.


I don't think that addresses are really a "concept" when talking about VFS, but the code has mention of struct address_space_operations, so we'll talk about it here.
struct address_space_operations {
        int (*writepage)(struct page *);
        int (*readpage)(struct file *, struct page *);
        int (*sync_page)(struct page *);
         * ext3 requires that a successful prepare_write() call be followed
         * by a commit_write() call - they must be balanced
        int (*prepare_write)(struct file *, struct page *, unsigned, unsigned);
        int (*commit_write)(struct file *, struct page *, unsigned, unsigned);
        /* Unfortunately this kludge is needed for FIBMAP. Don't use it */
        int (*bmap)(struct address_space *, long);
        int (*flushpage) (struct page *, unsigned long);
        int (*releasepage) (struct page *, int);
#define KERNEL_HAS_O_DIRECT /* this is for modules out of the kernel */
        int (*direct_IO)(int, struct inode *, struct kiobuf *, unsigned long, int);
        void (*removepage)(struct page *); /* called when page gets removed from the inode */
What's interesting here is that even a system like VFS, which seems nice and slick for what it does, still has to have special-case code through it. It's too bad, really.

The structure that's filled in ramfs:

static struct address_space_operations ramfs_aops = {
        readpage:       ramfs_readpage,
        writepage:      fail_writepage,
        prepare_write:  ramfs_prepare_write,
        commit_write:   ramfs_commit_write
One of the functions, fail_writepage(), isn't locally written, so I'll have to take a look at that later. The other three we shall look at now.

March 8, 2004

static int ramfs_readpage(struct file *file, struct page * page)
        if (!Page_Uptodate(page)) {
                memset(kmap(page), 0, PAGE_CACHE_SIZE);
        return 0;
Because ramfs is a ramdisk implementation, the above function is going to be very specific to this. All of the functions above have to do with memory management, so to fully understand the ramfs module, I'll have to look into that. Peeking into romfs, I see that the kmap() fetches a block of memory to fill (as passed in the struct page * page parameter). We seem to set it to zeroes(?) with memset(). Anyway, we'll come back to what we really ought to do with readpage() at a later time.
static int ramfs_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to)
        void *addr = kmap(page);
        if (!Page_Uptodate(page)) {
                memset(addr, 0, PAGE_CACHE_SIZE);
        return 0;
Similar to the ramfs_readpage(), this is mainly a bunch of memory management function calls. I'm not sure what's required for "preparing" yet.
static int ramfs_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to)
        struct inode *inode = page->mapping->host;
        loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;

        if (pos > inode->i_size)
                inode->i_size = pos;
        return 0;
Again, very ramfs-specific. Most VFS modules would probably take the struct page *page and write the data onto disk. ramfs, or course, can leave it in memory, since it's a ramdisk. romfs, of course, doesn't ALLOW a write, so there isn't an alternate example to take a look at. This still makes me wonder about what happens when a function isn't supplied -- you can't have a default WRITE function for filesystems! So it's null, and therefore nothing's called? And I guess VFS would have to take that as a "successful" function call? Or is a correct error code returned, such as should happen if you try to save something in a romfs filesystem? All good questions...

Well, that's practically all the code in ramfs/inode.c. There are still a lot of questions to be answered to really understand what's going on -- both in the ramfs module specifically, and in VFS modules generaally.
<--inodes ^--VFS--^ dentries-->

©2002-2018 Wayne Pearson