Commit f7a5d012 authored by Patrick Mochel's avatar Patrick Mochel

sysfs: split up inode.c into different files for different purposes.

- new files file.c, dir.c, symlink.c, mount.c.

- Purely cosmetic (for now). Should make it easier to add new filetypes.
parent f5fa274f
......@@ -2,6 +2,6 @@
# Makefile for the sysfs virtual filesystem
#
export-objs := inode.o
export-objs := file.o dir.o symlink.o
obj-y := inode.o
obj-y := inode.o file.o dir.o symlink.o mount.o
/*
* dir.c - Operations for sysfs directories.
*/
#undef DEBUG
#include <linux/fs.h>
#include <linux/mount.h>
#include <linux/module.h>
#include <linux/kobject.h>
#include "sysfs.h"
static int sysfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
int res;
mode = (mode & (S_IRWXUGO|S_ISVTX)) | S_IFDIR;
res = sysfs_mknod(dir, dentry, mode, 0);
if (!res)
dir->i_nlink++;
return res;
}
/**
* sysfs_create_dir - create a directory for an object.
* @parent: parent parent object.
* @kobj: object we're creating directory for.
*/
int sysfs_create_dir(struct kobject * kobj)
{
struct dentry * dentry = NULL;
struct dentry * parent;
int error = 0;
if (!kobj)
return -EINVAL;
if (kobj->parent)
parent = kobj->parent->dentry;
else if (sysfs_mount && sysfs_mount->mnt_sb)
parent = sysfs_mount->mnt_sb->s_root;
else
return -EFAULT;
down(&parent->d_inode->i_sem);
dentry = sysfs_get_dentry(parent,kobj->name);
if (!IS_ERR(dentry)) {
dentry->d_fsdata = (void *)kobj;
kobj->dentry = dentry;
error = sysfs_mkdir(parent->d_inode,dentry,
(S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO));
} else
error = PTR_ERR(dentry);
up(&parent->d_inode->i_sem);
return error;
}
/**
* sysfs_remove_dir - remove an object's directory.
* @kobj: object.
*
* The only thing special about this is that we remove any files in
* the directory before we remove the directory, and we've inlined
* what used to be sysfs_rmdir() below, instead of calling separately.
*/
void sysfs_remove_dir(struct kobject * kobj)
{
struct list_head * node, * next;
struct dentry * dentry = dget(kobj->dentry);
struct dentry * parent;
if (!dentry)
return;
pr_debug("sysfs %s: removing dir\n",dentry->d_name.name);
parent = dget(dentry->d_parent);
down(&parent->d_inode->i_sem);
down(&dentry->d_inode->i_sem);
list_for_each_safe(node,next,&dentry->d_subdirs) {
struct dentry * d = dget(list_entry(node,struct dentry,d_child));
/**
* Make sure dentry is still there
*/
pr_debug(" o %s: ",d->d_name.name);
if (d->d_inode) {
pr_debug("removing");
/**
* Unlink and unhash.
*/
simple_unlink(dentry->d_inode,d);
d_delete(d);
/**
* Drop reference from initial sysfs_get_dentry().
*/
dput(d);
}
pr_debug(" done (%d)\n",atomic_read(&d->d_count));
/**
* drop reference from dget() above.
*/
dput(d);
}
up(&dentry->d_inode->i_sem);
d_invalidate(dentry);
simple_rmdir(parent->d_inode,dentry);
d_delete(dentry);
pr_debug(" o %s removing done (%d)\n",dentry->d_name.name,
atomic_read(&dentry->d_count));
/**
* Drop reference from initial sysfs_get_dentry().
*/
dput(dentry);
/**
* Drop reference from dget() on entrance.
*/
dput(dentry);
up(&parent->d_inode->i_sem);
dput(parent);
}
EXPORT_SYMBOL(sysfs_create_dir);
EXPORT_SYMBOL(sysfs_remove_dir);
This diff is collapsed.
This diff is collapsed.
/*
* mount.c - operations for initializing and mounting sysfs.
*/
#include <linux/fs.h>
#include <linux/mount.h>
#include <linux/pagemap.h>
#include "sysfs.h"
/* Random magic number */
#define SYSFS_MAGIC 0x62656572
struct vfsmount *sysfs_mount;
static struct super_operations sysfs_ops = {
.statfs = simple_statfs,
.drop_inode = generic_delete_inode,
};
static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
{
struct inode *inode;
struct dentry *root;
sb->s_blocksize = PAGE_CACHE_SIZE;
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
sb->s_magic = SYSFS_MAGIC;
sb->s_op = &sysfs_ops;
inode = sysfs_get_inode(sb, S_IFDIR | 0755, 0);
if (!inode) {
pr_debug("%s: could not get inode!\n",__FUNCTION__);
return -ENOMEM;
}
root = d_alloc_root(inode);
if (!root) {
pr_debug("%s: could not get root dentry!\n",__FUNCTION__);
iput(inode);
return -ENOMEM;
}
sb->s_root = root;
return 0;
}
static struct super_block *sysfs_get_sb(struct file_system_type *fs_type,
int flags, char *dev_name, void *data)
{
return get_sb_single(fs_type, flags, data, sysfs_fill_super);
}
static struct file_system_type sysfs_fs_type = {
.name = "sysfs",
.get_sb = sysfs_get_sb,
.kill_sb = kill_litter_super,
};
static int __init sysfs_init(void)
{
int err;
err = register_filesystem(&sysfs_fs_type);
if (!err) {
sysfs_mount = kern_mount(&sysfs_fs_type);
if (IS_ERR(sysfs_mount)) {
printk(KERN_ERR "sysfs: could not mount!\n");
err = PTR_ERR(sysfs_mount);
sysfs_mount = NULL;
}
}
return err;
}
core_initcall(sysfs_init);
/*
* symlink.c - operations for sysfs symlinks.
*/
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/kobject.h>
#include "sysfs.h"
static int sysfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname)
{
struct inode *inode;
int error = -ENOSPC;
if (dentry->d_inode)
return -EEXIST;
inode = sysfs_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0);
if (inode) {
int l = strlen(symname)+1;
error = page_symlink(inode, symname, l);
if (!error) {
d_instantiate(dentry, inode);
dget(dentry);
} else
iput(inode);
}
return error;
}
static int object_depth(struct kobject * kobj)
{
struct kobject * p = kobj;
int depth = 0;
do { depth++; } while ((p = p->parent));
return depth;
}
static int object_path_length(struct kobject * kobj)
{
struct kobject * p = kobj;
int length = 1;
do {
length += strlen(p->name) + 1;
p = p->parent;
} while (p);
return length;
}
static void fill_object_path(struct kobject * kobj, char * buffer, int length)
{
struct kobject * p;
--length;
for (p = kobj; p; p = p->parent) {
int cur = strlen(p->name);
/* back up enough to print this bus id with '/' */
length -= cur;
strncpy(buffer + length,p->name,cur);
*(buffer + --length) = '/';
}
}
/**
* sysfs_create_link - create symlink between two objects.
* @kobj: object whose directory we're creating the link in.
* @target: object we're pointing to.
* @name: name of the symlink.
*/
int sysfs_create_link(struct kobject * kobj, struct kobject * target, char * name)
{
struct dentry * dentry = kobj->dentry;
struct dentry * d;
int error = 0;
int size;
int depth;
char * path;
char * s;
depth = object_depth(kobj);
size = object_path_length(target) + depth * 3 - 1;
if (size > PATH_MAX)
return -ENAMETOOLONG;
pr_debug("%s: depth = %d, size = %d\n",__FUNCTION__,depth,size);
path = kmalloc(size,GFP_KERNEL);
if (!path)
return -ENOMEM;
memset(path,0,size);
for (s = path; depth--; s += 3)
strcpy(s,"../");
fill_object_path(target,path,size);
pr_debug("%s: path = '%s'\n",__FUNCTION__,path);
down(&dentry->d_inode->i_sem);
d = sysfs_get_dentry(dentry,name);
if (!IS_ERR(d))
error = sysfs_symlink(dentry->d_inode,d,path);
else
error = PTR_ERR(d);
up(&dentry->d_inode->i_sem);
kfree(path);
return error;
}
/**
* sysfs_remove_link - remove symlink in object's directory.
* @kobj: object we're acting for.
* @name: name of the symlink to remove.
*/
void sysfs_remove_link(struct kobject * kobj, char * name)
{
sysfs_hash_and_remove(kobj->dentry,name);
}
EXPORT_SYMBOL(sysfs_create_link);
EXPORT_SYMBOL(sysfs_remove_link);
extern struct vfsmount * sysfs_mount;
extern struct inode *sysfs_get_inode(struct super_block *sb, int mode, int dev);
extern int sysfs_mknod(struct inode *, struct dentry *, int, dev_t);
extern struct dentry * sysfs_get_dentry(struct dentry *, char *);
extern void sysfs_hash_and_remove(struct dentry * dir, const char * name);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment