|
|
Log in / Subscribe / Register

lwnfs simpler source 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.  This is the extra
 * simple version without subdirectories.
 *
 * Copyright 2002, 2003 Jonathan Corbet <corbet-AT-lwn.net>
 * 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 <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>     	/* This is where libfs stuff is declared */
#include <asm/atomic.h>
#include <asm/uaccess.h>	/* copy_to_user */

/*
 * Boilerplate stuff.
 */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jonathan Corbet");

#define LFS_MAGIC 0x19980122

/*
 * Implement an array of counters.
 */
#define NCOUNTERS 4
static atomic_t counters[NCOUNTERS];



/*
 * The operations on our "files".
 */

/*
 * Open a file.  All we have to do here is to copy over a
 * copy of the counter pointer so it's easier to get at.
 */
static int lfs_open(struct inode *inode, struct file *filp)
{
	if (inode->i_ino > NCOUNTERS)
		return -ENODEV;  /* Should never happen.  */
	filp->private_data = counters + inode->i_ino - 1;
	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)
{
	int v, len;
	char tmp[TMPSIZE];
	atomic_t *counter = (atomic_t *) filp->private_data;
/*
 * 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)
{
	char tmp[TMPSIZE];
	atomic_t *counter = (atomic_t *) filp->private_data;
/*
 * 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,
};




/*
 * OK, create the files that we export.
 */
struct tree_descr OurFiles[] = {
	{ NULL, NULL, 0 },  /* Skipped */
	{ .name = "counter0",
	  .ops = &lfs_file_ops,
	  .mode = S_IWUSR|S_IRUGO },
	{ .name = "counter1",
	  .ops = &lfs_file_ops,
	  .mode = S_IWUSR|S_IRUGO },
	{ .name = "counter2",
	  .ops = &lfs_file_ops,
	  .mode = S_IWUSR|S_IRUGO },
	{ .name = "counter3",
	  .ops = &lfs_file_ops,
	  .mode = S_IWUSR|S_IRUGO },
	{ "", NULL, 0 }
};



/*
 * Superblock stuff.  This is all boilerplate to give the vfs something
 * that looks like a filesystem to work with.
 */

/*
 * "Fill" a superblock with mundane stuff.
 */
static int lfs_fill_super (struct super_block *sb, void *data, int silent)
{
	return simple_fill_super(sb, LFS_MAGIC, OurFiles);
}


/*
 * 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)
{
	int i;

	for (i = 0; i < NCOUNTERS; i++)
		atomic_set(counters + i, 0);
	return register_filesystem(&lfs_type);
}

static void __exit lfs_exit(void)
{
	unregister_filesystem(&lfs_type);
}

module_init(lfs_init);
module_exit(lfs_exit);



to post comments

lwnfs simpler source code

Posted Feb 9, 2009 17:30 UTC (Mon) by cbrannon (guest, #56557) [Link] (2 responses)

Here's a diff for this source file.

--- lwnfs_simple1.c 2009-02-09 11:16:04.000000000 -0600
+++ lwnfs_simple2.c 2009-02-09 11:29:42.000000000 -0600
@@ -9,6 +9,12 @@
* nethack high scores, and set your disk drives on fire. You have
* been warned.
*/
+
+/*
+ * Return type of lfs_get_super should be int.
+ * lfs_get_super and get_sb_single need a parameter of type struct vfsmount *
+ * Chris Brannon, 02/09/2009
+*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -154,10 +160,11 @@
/*
* 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)
+static int lfs_get_super(struct file_system_type *fst,
+ int flags, const char *devname, void *data,
+ struct vfsmount *mount)
{
- return get_sb_single(fst, flags, data, lfs_fill_super);
+ return get_sb_single(fst, flags, data, lfs_fill_super, mount);
}

static struct file_system_type lfs_type = {

lwnfs simpler source code

Posted Jan 22, 2015 22:36 UTC (Thu) by wzab (guest, #100724) [Link] (1 responses)

To compile the code with the 3.16 kernel, I had to introduce more modifications.
Below is the diff file (please note, that leading spaces are removed when comment is posted, so probably you will not be able to use this file directly as a patch, you'll need to enter changes manually):

--- lwns_simple1.c 2015-01-22 23:28:44.018034566 +0100
+++ lwnfs_simple2.c 2015-01-22 23:28:22.818033293 +0100
@@ -163,16 +163,17 @@
/*
* 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)
+
+struct dentry *lfs_mount(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data)
{
- return get_sb_single(fst, flags, data, lfs_fill_super);
+ return mount_nodev(fs_type, flags, data, lfs_fill_super);
}

static struct file_system_type lfs_type = {
.owner = THIS_MODULE,
.name = "lwnfs",
- .get_sb = lfs_get_super,
+ .mount = lfs_mount,
.kill_sb = kill_litter_super,
};

lwnfs simpler source code

Posted Jan 23, 2015 12:12 UTC (Fri) by cladisch (✭ supporter ✭, #50193) [Link]

Correctly formatted, and with small fixes:
--- lwnfs_simple1.c
+++ lwnfs_simple2.c
@@ -163,16 +163,16 @@
 /*
  * Stuff to pass in when registering the filesystem.
  */
-static struct super_block *lfs_get_super(struct file_system_type *fst,
+static struct dentry *lfs_mount(struct file_system_type *fst,
 		int flags, const char *devname, void *data)
 {
-	return get_sb_single(fst, flags, data, lfs_fill_super);
+	return mount_nodev(fst, flags, data, lfs_fill_super);
 }
 
 static struct file_system_type lfs_type = {
 	.owner 		= THIS_MODULE,
 	.name		= "lwnfs",
-	.get_sb		= lfs_get_super,
+	.mount		= lfs_mount,
 	.kill_sb	= kill_litter_super,
 };
 


Copyright © 2003, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds