CODE: This is the "lwnfs" module source which goes along with this article on virtual filesystems from the Porting Drivers to 2.6 series.
/* * Demonstrate a trivial filesystem using libfs. * * Copyright 2002,200 3 Jonathan Corbet * This file may be redistributed under the terms of the gnu gpl. * * Chances are that this code will crash your system, delete your * Nethack high scores, and set your disk drives on fire. You have * Been warned. */ # Include # Include # Include # Include /* PAGE_CACHE_SIZE */ # Include /* This is where libfs stuff is declared */ # Include # Include/* copy_to_user */ /* * Boilerplate stuff. */ MODULE_LICENSE ("GPL "); MODULE_AUTHOR ("Jonathan Corbet "); # Define LFS_MAGIC 0x19980122 /* * Anytime we make a file or directory in our filesystem we need * Come up with an inode to represent it internally. This is * The function that does that job. All that's really interesting * Is the "mode" parameter, which says whether this is a directory * Or file, and gives the permissions. */ Static struct inode * lfs_make_inode (struct super_block * sb, int mode) { Struct inode * ret = new_inode (sb ); If (ret ){ Ret-> I _mode = mode; Ret-> I _uid = ret-> I _gid = 0; Ret-> I _blksize = PAGE_CACHE_SIZE; Ret-> I _blocks = 0; Ret-> I _atime = ret-> I _mtime = ret-> I _ctime = CURRENT_TIME; } Return ret; } /* * The operations on our "files ". */ /* * Open a file. All we have to do here is to copy over * Copy of the counter pointer so it's easier to get. */ Static int lfs_open (struct inode * inode, struct file * filp) { Filp-> private_data = inode-> u. generic_ip; Return 0; } # Define TMPSIZE 20 /* * Read a file. Here we increment and read the counter, then pass it * Back to the caller. The increment only happens if the read is done * At the beginning of the file (offset = 0); otherwise we end up counting * By twos. */ Static ssize_t lfs_read_file (struct file * filp, char * buf, Size_t count, loff_t * offset) { Atomic_t * counter = (atomic_t *) filp-> private_data; Int v, len; Char tmp [TMPSIZE]; /* * Encode the value, and figure out how much of it we can pass back. */ V = atomic_read (counter ); If (* offset> 0) V-= 1;/* the value returned when offset was zero */ Else Atomic_inc (counter ); Len = snprintf (tmp, TMPSIZE, "% d \ n", v ); If (* offset> len) Return 0; If (count> len-* offset) Count = len-* offset; /* * Copy it back, increment the offset, and we're done. */ If (copy_to_user (buf, tmp + * offset, count )) Return-EFAULT; * Offset + = count; Return count; } /* * Write a file. */ Static ssize_t lfs_write_file (struct file * filp, const char * buf, Size_t count, loff_t * offset) { Atomic_t * counter = (atomic_t *) filp-> private_data; Char tmp [TMPSIZE]; /* * Only write from the beginning. */ If (* offset! = 0) Return-EINVAL; /* * Read the value from the user. */ If (count> = TMPSIZE) Return-EINVAL; Memset (tmp, 0, TMPSIZE ); If (copy_from_user (tmp, buf, count )) Return-EFAULT; /* * Store it in the counter and we are done. */ Atomic_set (counter, simple_strtol (tmp, NULL, 10 )); Return count; } /* * Now we can put together our file operations structure. */ Static struct file_operations lfs_file_ops = { . Open = lfs_open, . Read = lfs_read_file, . Write = lfs_write_file, }; /* * Create a file mapping a name to a counter. */ Static struct dentry * lfs_create_file (struct super_block * sb, Struct dentry * dir, const char * name, Atomic_t * counter) { Struct dentry * dentry; Struct inode * inode; Struct qstr qname; /* * Make a hashed version of the name to go with the dentry. */ Qname. name = name; Qname. len = strlen (name ); Qname. hash = full_name_hash (name, qname. len ); /* * Now we can create our dentry and the inode to go with it. */ Dentry = d_alloc (dir, & qname ); If (! Dentry) Goto out; Inode = lfs_make_inode (sb, S_IFREG | 0644 ); If (! Inode) Goto out_dput; Inode-> I _fop = & lfs_file_ops; Inode-> u. generic_ip = counter; /* * Put it all into the dentry cache and we're all done. */ D_add (dentry, inode ); Return dentry; /* * Then again, maybe it didn't work. */ Out_dput: Dput (dentry ); Out: Return 0; } /* * Create a directory which can be used to hold files. This code is * Almost identical to the "create file" logic, doesn't that we create * The inode with a different mode, and use the libfs "simple" operations. */ Static struct dentry * lfs_create_dir (struct super_block * sb, Struct dentry * parent, const char * name) { Struct dentry * dentry; Struct inode * inode; Struct qstr qname; Qname. name = name; Qname. len = strlen (name ); Qname. hash = full_name_hash (name, qname. len ); Dentry = d_alloc (parent, & qname ); If (! Dentry) Goto out; Inode = lfs_make_inode (sb, S_IFDIR | 0644 ); If (! Inode) Goto out_dput; Inode-> I _op = & simple_dir_inode_operations; Inode-> I _fop = & simple_dir_operations; D_add (dentry, inode ); Return dentry; Out_dput: Dput (dentry ); Out: Return 0; } /* * OK, create the files that we export. */ Static atomic_t counter, subcounter; Static void lfs_create_files (struct super_block * sb, struct dentry * root) { Struct dentry * subdir; /* * One counter in the top-level directory. */ Atomic_set (& counter, 0 ); Lfs_create_file (sb, root, "counter", & counter ); /* * And one in a subdirectory. */ Atomic_set (& subcounter, 0 ); Subdir = lfs_create_dir (sb, root, "subdir "); If (subdir) Lfs_create_file (sb, subdir, "subcounter", & subcounter ); } /* * Superblock stuff. This is all boilerplate to give the vfs something * That looks like a filesystem to work. */ /* * Our superblock operations, both of which are generic kernel ops * That we don't have to write ourselves. */ Static struct super_operations lfs_s_ops = { . Statfs = simple_statfs, . Drop_inode = generic_delete_inode, }; /* * "Fill" a superblock with mundane stuff. */ Static int lfs_fill_super (struct super_block * sb, void * data, int silent) { Struct inode * root; Struct dentry * root_dentry; /* * Basic parameters. */ Sb-> s_blocksize = PAGE_CACHE_SIZE; Sb-> s_blocksize_bits = PAGE_CACHE_SHIFT; Sb-> s_magic = LFS_MAGIC; Sb-> s_op = & lfs_ops; /* * We need to conjure up an inode to represent the root directory * Of this filesystem. Its operations all come from libfs, so we * Don't have to mess with actually * doing * things inside this * Directory. */ Root = lfs_make_inode (sb, S_IFDIR | 0755 ); If (! Root) Goto out; Root-> I _op = & simple_dir_inode_operations; Root-> I _fop = & simple_dir_operations; /* * Get a dentry to represent the directory in core. */ Root_dentry = d_alloc_root (root ); If (! Root_dentry) Goto out_iput; Sb-> s_root = root_dentry; /* * Make up the files which will be in this filesystem, and we're re done. */ Lfs_create_files (sb, root_dentry ); Return 0; Out_iput: Iput (root ); Out: Return-ENOMEM; } /* * Stuff to pass in when registering the filesystem. */ Static struct super_block * lfs_get_super (struct file_system_type * fst, Int flags, const char * devname, void * data) { Return get_sb_single (fst, flags, data, lfs_fill_super ); } Static struct file_system_type lfs_type = { . Owner = THIS_MODULE, . Name = "lwnfs ", . Get_sb = lfs_get_super, . Kill_sb = kill_litter_super, }; /* * Get things set up. */ Static int _ init lfs_init (void) { Return register_filesystem (& lfs_type ); } Static void _ exit lfs_exit (void) { Unregister_filesystem (& lfs_type ); } Module_init (lfs_init ); Module_exit (lfs_exit ); |