Commit d2f8eca7 authored by Patrick Mochel's avatar Patrick Mochel

Merge osdl.org:/home/mochel/src/kernel/devel/linux-2.5-virgin

into osdl.org:/home/mochel/src/kernel/devel/linux-2.5-kobject
parents d8c084f9 eda52025
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/backing-dev.h> #include <linux/backing-dev.h>
#include <linux/sysfs.h> #include <linux/kobject.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -42,7 +42,6 @@ ...@@ -42,7 +42,6 @@
static struct super_operations sysfs_ops; static struct super_operations sysfs_ops;
static struct file_operations sysfs_file_operations; static struct file_operations sysfs_file_operations;
static struct inode_operations sysfs_dir_inode_operations;
static struct address_space_operations sysfs_aops; static struct address_space_operations sysfs_aops;
static struct vfsmount *sysfs_mount; static struct vfsmount *sysfs_mount;
...@@ -52,45 +51,6 @@ static struct backing_dev_info sysfs_backing_dev_info = { ...@@ -52,45 +51,6 @@ static struct backing_dev_info sysfs_backing_dev_info = {
.memory_backed = 1, /* Does not contribute to dirty memory */ .memory_backed = 1, /* Does not contribute to dirty memory */
}; };
static int sysfs_readpage(struct file *file, struct page * page)
{
if (!PageUptodate(page)) {
void *kaddr = kmap_atomic(page, KM_USER0);
memset(kaddr, 0, PAGE_CACHE_SIZE);
flush_dcache_page(page);
kunmap_atomic(kaddr, KM_USER0);
SetPageUptodate(page);
}
unlock_page(page);
return 0;
}
static int sysfs_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to)
{
if (!PageUptodate(page)) {
void *kaddr = kmap_atomic(page, KM_USER0);
memset(kaddr, 0, PAGE_CACHE_SIZE);
flush_dcache_page(page);
kunmap_atomic(kaddr, KM_USER0);
SetPageUptodate(page);
}
return 0;
}
static int sysfs_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;
set_page_dirty(page);
if (pos > inode->i_size)
inode->i_size = pos;
return 0;
}
static struct inode *sysfs_get_inode(struct super_block *sb, int mode, int dev) static struct inode *sysfs_get_inode(struct super_block *sb, int mode, int dev)
{ {
struct inode *inode = new_inode(sb); struct inode *inode = new_inode(sb);
...@@ -113,7 +73,7 @@ static struct inode *sysfs_get_inode(struct super_block *sb, int mode, int dev) ...@@ -113,7 +73,7 @@ static struct inode *sysfs_get_inode(struct super_block *sb, int mode, int dev)
inode->i_fop = &sysfs_file_operations; inode->i_fop = &sysfs_file_operations;
break; break;
case S_IFDIR: case S_IFDIR:
inode->i_op = &sysfs_dir_inode_operations; inode->i_op = &simple_dir_inode_operations;
inode->i_fop = &simple_dir_operations; inode->i_fop = &simple_dir_operations;
/* directory inodes start off with i_nlink == 2 (for "." entry) */ /* directory inodes start off with i_nlink == 2 (for "." entry) */
...@@ -182,29 +142,6 @@ static int sysfs_symlink(struct inode * dir, struct dentry *dentry, const char * ...@@ -182,29 +142,6 @@ static int sysfs_symlink(struct inode * dir, struct dentry *dentry, const char *
return error; return error;
} }
static inline int sysfs_positive(struct dentry *dentry)
{
return (dentry->d_inode && !d_unhashed(dentry));
}
static int sysfs_empty(struct dentry *dentry)
{
struct list_head *list;
spin_lock(&dcache_lock);
list_for_each(list, &dentry->d_subdirs) {
struct dentry *de = list_entry(list, struct dentry, d_child);
if (sysfs_positive(de)) {
spin_unlock(&dcache_lock);
return 0;
}
}
spin_unlock(&dcache_lock);
return 1;
}
static int sysfs_unlink(struct inode *dir, struct dentry *dentry) static int sysfs_unlink(struct inode *dir, struct dentry *dentry)
{ {
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
...@@ -217,30 +154,35 @@ static int sysfs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -217,30 +154,35 @@ static int sysfs_unlink(struct inode *dir, struct dentry *dentry)
} }
/** /**
* sysfs_read_file - "read" data from a file. * sysfs_read_file - read an attribute.
* @file: file pointer * @file: file pointer.
* @buf: buffer to fill * @buf: buffer to fill.
* @count: number of bytes to read * @count: number of bytes to read.
* @ppos: starting offset in file * @ppos: starting offset in file.
*
* Userspace wants to read an attribute file. The attribute descriptor
* is in the file's ->d_fsdata. The target object is in the directory's
* ->d_fsdata.
* *
* Userspace wants data from a file. It is up to the creator of the file to * We allocate a %PAGE_SIZE buffer, and pass it to the object's ->show()
* provide that data. * method (along with the object). We loop doing this until @count is
* There is a struct device_attribute embedded in file->private_data. We * satisfied, or ->show() returns %0.
* obtain that and check if the read callback is implemented. If so, we call
* it, passing the data field of the file entry.
* Said callback is responsible for filling the buffer and returning the number
* of bytes it put in it. We update @ppos correctly.
*/ */
static ssize_t static ssize_t
sysfs_read_file(struct file *file, char *buf, size_t count, loff_t *ppos) sysfs_read_file(struct file *file, char *buf, size_t count, loff_t *ppos)
{ {
struct attribute * attr = file->f_dentry->d_fsdata; struct attribute * attr = file->f_dentry->d_fsdata;
struct driver_dir_entry * dir; struct sysfs_ops * ops = NULL;
struct kobject * kobj;
unsigned char *page; unsigned char *page;
ssize_t retval = 0; ssize_t retval = 0;
dir = file->f_dentry->d_parent->d_fsdata; kobj = file->f_dentry->d_parent->d_fsdata;
if (!dir->ops->show) if (kobj)
ops = kobj->dir.ops;
if (!ops || !ops->show)
return 0; return 0;
if (count > PAGE_SIZE) if (count > PAGE_SIZE)
...@@ -253,7 +195,7 @@ sysfs_read_file(struct file *file, char *buf, size_t count, loff_t *ppos) ...@@ -253,7 +195,7 @@ sysfs_read_file(struct file *file, char *buf, size_t count, loff_t *ppos)
while (count > 0) { while (count > 0) {
ssize_t len; ssize_t len;
len = dir->ops->show(dir,attr,page,count,*ppos); len = ops->show(kobj,attr,page,count,*ppos);
if (len <= 0) { if (len <= 0) {
if (len < 0) if (len < 0)
...@@ -277,27 +219,32 @@ sysfs_read_file(struct file *file, char *buf, size_t count, loff_t *ppos) ...@@ -277,27 +219,32 @@ sysfs_read_file(struct file *file, char *buf, size_t count, loff_t *ppos)
} }
/** /**
* sysfs_write_file - "write" to a file * sysfs_write_file - write an attribute.
* @file: file pointer * @file: file pointer
* @buf: data to write * @buf: data to write
* @count: number of bytes * @count: number of bytes
* @ppos: starting offset * @ppos: starting offset
* *
* Similarly to sysfs_read_file, we act essentially as a bit pipe. * Identical to sysfs_read_file(), though going the opposite direction.
* We check for a "write" callback in file->private_data, and pass * We allocate a %PAGE_SIZE buffer and copy in the userspace buffer. We
* @buffer, @count, @ppos, and the file entry's data to the callback. * pass that to the object's ->store() method until we reach @count or
* The number of bytes written is returned, and we handle updating * ->store() returns %0 or less.
* @ppos properly.
*/ */
static ssize_t static ssize_t
sysfs_write_file(struct file *file, const char *buf, size_t count, loff_t *ppos) sysfs_write_file(struct file *file, const char *buf, size_t count, loff_t *ppos)
{ {
struct attribute * attr = file->f_dentry->d_fsdata; struct attribute * attr = file->f_dentry->d_fsdata;
struct driver_dir_entry * dir; struct sysfs_ops * ops = NULL;
struct kobject * kobj;
ssize_t retval = 0; ssize_t retval = 0;
char * page; char * page;
dir = file->f_dentry->d_parent->d_fsdata; kobj = file->f_dentry->d_parent->d_fsdata;
if (kobj)
ops = kobj->dir.ops;
if (!ops || !ops->store)
return 0;
page = (char *)__get_free_page(GFP_KERNEL); page = (char *)__get_free_page(GFP_KERNEL);
if (!page) if (!page)
...@@ -312,7 +259,7 @@ sysfs_write_file(struct file *file, const char *buf, size_t count, loff_t *ppos) ...@@ -312,7 +259,7 @@ sysfs_write_file(struct file *file, const char *buf, size_t count, loff_t *ppos)
while (count > 0) { while (count > 0) {
ssize_t len; ssize_t len;
len = dir->ops->store(dir,attr,page + retval,count,*ppos); len = ops->store(kobj,attr,page + retval,count,*ppos);
if (len <= 0) { if (len <= 0) {
if (len < 0) if (len < 0)
...@@ -329,77 +276,42 @@ sysfs_write_file(struct file *file, const char *buf, size_t count, loff_t *ppos) ...@@ -329,77 +276,42 @@ sysfs_write_file(struct file *file, const char *buf, size_t count, loff_t *ppos)
return retval; return retval;
} }
static loff_t
sysfs_file_lseek(struct file *file, loff_t offset, int orig)
{
loff_t retval = -EINVAL;
down(&file->f_dentry->d_inode->i_sem);
switch(orig) {
case 0:
if (offset > 0) {
file->f_pos = offset;
retval = file->f_pos;
}
break;
case 1:
if ((offset + file->f_pos) > 0) {
file->f_pos += offset;
retval = file->f_pos;
}
break;
default:
break;
}
up(&file->f_dentry->d_inode->i_sem);
return retval;
}
static int sysfs_open_file(struct inode * inode, struct file * filp) static int sysfs_open_file(struct inode * inode, struct file * filp)
{ {
struct driver_dir_entry * dir; struct kobject * kobj;
int error = 0; int error = 0;
dir = (struct driver_dir_entry *)filp->f_dentry->d_parent->d_fsdata; kobj = filp->f_dentry->d_parent->d_fsdata;
if (dir) { if ((kobj = kobject_get(kobj))) {
struct attribute * attr = filp->f_dentry->d_fsdata; struct attribute * attr = filp->f_dentry->d_fsdata;
if (attr && dir->ops) { if (!attr)
if (dir->ops->open) error = -EINVAL;
error = dir->ops->open(dir); } else
goto Done; error = -EINVAL;
}
}
error = -EINVAL;
Done:
return error; return error;
} }
static int sysfs_release(struct inode * inode, struct file * filp) static int sysfs_release(struct inode * inode, struct file * filp)
{ {
struct driver_dir_entry * dir; struct kobject * kobj = filp->f_dentry->d_parent->d_fsdata;
dir = (struct driver_dir_entry *)filp->f_dentry->d_parent->d_fsdata; if (kobj)
if (dir->ops->close) kobject_put(kobj);
dir->ops->close(dir);
return 0; return 0;
} }
static struct file_operations sysfs_file_operations = { static struct file_operations sysfs_file_operations = {
.read = sysfs_read_file, .read = sysfs_read_file,
.write = sysfs_write_file, .write = sysfs_write_file,
.llseek = sysfs_file_lseek, .llseek = generic_file_llseek,
.open = sysfs_open_file, .open = sysfs_open_file,
.release = sysfs_release, .release = sysfs_release,
}; };
static struct inode_operations sysfs_dir_inode_operations = {
.lookup = simple_lookup,
};
static struct address_space_operations sysfs_aops = { static struct address_space_operations sysfs_aops = {
.readpage = sysfs_readpage, .readpage = simple_readpage,
.writepage = fail_writepage, .writepage = fail_writepage,
.prepare_write = sysfs_prepare_write, .prepare_write = simple_prepare_write,
.commit_write = sysfs_commit_write .commit_write = simple_commit_write
}; };
static struct super_operations sysfs_ops = { static struct super_operations sysfs_ops = {
...@@ -464,6 +376,7 @@ static int __init sysfs_init(void) ...@@ -464,6 +376,7 @@ static int __init sysfs_init(void)
core_initcall(sysfs_init); core_initcall(sysfs_init);
static struct dentry * get_dentry(struct dentry * parent, const char * name) static struct dentry * get_dentry(struct dentry * parent, const char * name)
{ {
struct qstr qstr; struct qstr qstr;
...@@ -474,137 +387,160 @@ static struct dentry * get_dentry(struct dentry * parent, const char * name) ...@@ -474,137 +387,160 @@ static struct dentry * get_dentry(struct dentry * parent, const char * name)
return lookup_hash(&qstr,parent); return lookup_hash(&qstr,parent);
} }
/** /**
* sysfs_create_dir - create a directory in the filesystem * sysfs_create_dir - create a directory for an object.
* @entry: directory entry * @parent: parent parent object.
* @parent: parent directory entry * @kobj: object we're creating directory for.
*/ */
int
sysfs_create_dir(struct driver_dir_entry * entry, int sysfs_create_dir(struct kobject * kobj)
struct driver_dir_entry * parent)
{ {
struct dentry * dentry = NULL; struct dentry * dentry = NULL;
struct dentry * parent_dentry; struct dentry * parent;
int error = 0; int error = 0;
if (!entry) if (!kobj)
return -EINVAL; return -EINVAL;
parent_dentry = parent ? parent->dentry : NULL; if (kobj->parent)
parent = kobj->parent->dir.dentry;
if (!parent_dentry) else if (sysfs_mount && sysfs_mount->mnt_sb)
if (sysfs_mount && sysfs_mount->mnt_sb) parent = sysfs_mount->mnt_sb->s_root;
parent_dentry = sysfs_mount->mnt_sb->s_root; else
if (!parent_dentry)
return -EFAULT; return -EFAULT;
down(&parent_dentry->d_inode->i_sem); down(&parent->d_inode->i_sem);
dentry = get_dentry(parent_dentry,entry->name); dentry = get_dentry(parent,kobj->name);
if (!IS_ERR(dentry)) { if (!IS_ERR(dentry)) {
dentry->d_fsdata = (void *) entry; dentry->d_fsdata = (void *)kobj;
entry->dentry = dentry; kobj->dir.dentry = dentry;
error = sysfs_mkdir(parent_dentry->d_inode,dentry,entry->mode); error = sysfs_mkdir(parent->d_inode,dentry,
(S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO));
} else } else
error = PTR_ERR(dentry); error = PTR_ERR(dentry);
up(&parent_dentry->d_inode->i_sem); up(&parent->d_inode->i_sem);
return error; return error;
} }
/** /**
* sysfs_create_file - create a file * sysfs_create_file - create an attribute file for an object.
* @entry: structure describing the file * @kobj: object we're creating for.
* @parent: directory to create it in * @attr: atrribute descriptor.
*/ */
int
sysfs_create_file(struct attribute * entry, int sysfs_create_file(struct kobject * kobj, struct attribute * attr)
struct driver_dir_entry * parent)
{ {
struct dentry * dentry; struct dentry * dentry;
struct dentry * parent;
int error = 0; int error = 0;
if (!entry || !parent) if (!kobj || !attr)
return -EINVAL; return -EINVAL;
if (!parent->dentry) if (kobj->parent)
return -EINVAL; parent = kobj->parent->dir.dentry;
else
return -ENOENT;
down(&parent->dentry->d_inode->i_sem); down(&parent->d_inode->i_sem);
dentry = get_dentry(parent->dentry,entry->name); dentry = get_dentry(parent,attr->name);
if (!IS_ERR(dentry)) { if (!IS_ERR(dentry)) {
dentry->d_fsdata = (void *)entry; dentry->d_fsdata = (void *)attr;
error = sysfs_create(parent->dentry->d_inode,dentry,entry->mode); error = sysfs_create(parent->d_inode,dentry,attr->mode);
} else } else
error = PTR_ERR(dentry); error = PTR_ERR(dentry);
up(&parent->dentry->d_inode->i_sem); up(&parent->d_inode->i_sem);
return error; return error;
} }
/** /**
* sysfs_create_symlink - make a symlink * sysfs_create_symlink - make a symlink
* @parent: directory we're creating in * @kobj: object who's directory we're creating in.
* @entry: entry describing link * @name: name of the symlink.
* @target: place we're symlinking to * @target: path we're pointing to.
*
*/ */
int sysfs_create_symlink(struct driver_dir_entry * parent,
char * name, char * target) int sysfs_create_link(struct kobject * kobj, char * name, char * target)
{ {
struct dentry * dentry; struct dentry * dentry;
int error = 0; int error;
if (!parent || !parent->dentry) if (kobj) {
return -EINVAL; struct dentry * parent = kobj->dir.dentry;
down(&parent->dentry->d_inode->i_sem); down(&parent->d_inode->i_sem);
dentry = get_dentry(parent->dentry,name); dentry = get_dentry(parent,name);
if (!IS_ERR(dentry)) if (!IS_ERR(dentry))
error = sysfs_symlink(parent->dentry->d_inode,dentry,target); error = sysfs_symlink(parent->d_inode,dentry,target);
else else
error = PTR_ERR(dentry); error = PTR_ERR(dentry);
up(&parent->dentry->d_inode->i_sem); up(&parent->d_inode->i_sem);
} else
error = -EINVAL;
return error; return error;
} }
static void hash_and_remove(struct dentry * dir, const char * name)
{
struct dentry * victim;
down(&dir->d_inode->i_sem);
victim = get_dentry(dir,name);
if (!IS_ERR(victim)) {
/* make sure dentry is really there */
if (victim->d_inode &&
(victim->d_parent->d_inode == dir->d_inode)) {
sysfs_unlink(dir->d_inode,victim);
}
}
up(&dir->d_inode->i_sem);
}
/** /**
* sysfs_remove_file - exported file removal * sysfs_remove_file - remove an object attribute.
* @dir: directory the file supposedly resides in * @kobj: object we're acting for.
* @name: name of the file * @attr: attribute descriptor.
* *
* Try and find the file in the dir's list. * Hash the attribute name and kill the victim.
* If it's there, call __remove_file() (above) for the dentry.
*/ */
void sysfs_remove_file(struct driver_dir_entry * dir, const char * name)
void sysfs_remove_file(struct kobject * kobj, struct attribute * attr)
{ {
struct dentry * dentry; hash_and_remove(kobj->dir.dentry,attr->name);
}
if (!dir->dentry)
return;
down(&dir->dentry->d_inode->i_sem); /**
dentry = get_dentry(dir->dentry,name); * sysfs_remove_link - remove symlink in object's directory.
if (!IS_ERR(dentry)) { * @kobj: object we're acting for.
/* make sure dentry is really there */ * @name: name of the symlink to remove.
if (dentry->d_inode && */
(dentry->d_parent->d_inode == dir->dentry->d_inode)) {
sysfs_unlink(dir->dentry->d_inode,dentry); void sysfs_remove_link(struct kobject * kobj, char * name)
} {
} hash_and_remove(kobj->dir.dentry,name);
up(&dir->dentry->d_inode->i_sem);
} }
/** /**
* sysfs_remove_dir - exportable directory removal * sysfs_remove_dir - remove an object's directory.
* @dir: directory to remove * @kobj: object.
* *
* To make sure we don't orphan anyone, first remove * The only thing special about this is that we remove any files in
* all the children in the list, then do clean up the directory. * 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 driver_dir_entry * dir)
void sysfs_remove_dir(struct kobject * kobj)
{ {
struct list_head * node, * next; struct list_head * node, * next;
struct dentry * dentry = dir->dentry; struct dentry * dentry = kobj->dir.dentry;
struct dentry * parent; struct dentry * parent;
if (!dentry) if (!dentry)
...@@ -622,7 +558,7 @@ void sysfs_remove_dir(struct driver_dir_entry * dir) ...@@ -622,7 +558,7 @@ void sysfs_remove_dir(struct driver_dir_entry * dir)
} }
d_invalidate(dentry); d_invalidate(dentry);
if (sysfs_empty(dentry)) { if (simple_empty(dentry)) {
dentry->d_inode->i_nlink -= 2; dentry->d_inode->i_nlink -= 2;
dentry->d_inode->i_flags |= S_DEAD; dentry->d_inode->i_flags |= S_DEAD;
parent->d_inode->i_nlink--; parent->d_inode->i_nlink--;
...@@ -635,8 +571,9 @@ void sysfs_remove_dir(struct driver_dir_entry * dir) ...@@ -635,8 +571,9 @@ void sysfs_remove_dir(struct driver_dir_entry * dir)
} }
EXPORT_SYMBOL(sysfs_create_file); EXPORT_SYMBOL(sysfs_create_file);
EXPORT_SYMBOL(sysfs_create_symlink);
EXPORT_SYMBOL(sysfs_create_dir);
EXPORT_SYMBOL(sysfs_remove_file); EXPORT_SYMBOL(sysfs_remove_file);
EXPORT_SYMBOL(sysfs_create_link);
EXPORT_SYMBOL(sysfs_remove_link);
EXPORT_SYMBOL(sysfs_create_dir);
EXPORT_SYMBOL(sysfs_remove_dir); EXPORT_SYMBOL(sysfs_remove_dir);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/*
* kobject.h - generic kernel object infrastructure.
*
*/
#ifndef _KOBJECT_H_
#define _KOBJECT_H_
#include <linux/types.h>
#include <linux/list.h>
#include <linux/sysfs.h>
#include <asm/atomic.h>
struct kobject {
char name[16];
atomic_t refcount;
struct list_head entry;
struct kobject * parent;
struct sysfs_dir dir;
};
extern void kobject_init(struct kobject *);
extern int kobject_register(struct kobject *);
extern void kobject_unregister(struct kobject *);
extern struct kobject * kobject_get(struct kobject *);
extern void kobject_put(struct kobject *);
#endif /* _KOBJECT_H_ */
...@@ -11,18 +11,15 @@ ...@@ -11,18 +11,15 @@
struct driver_dir_entry; struct driver_dir_entry;
struct attribute; struct attribute;
struct kobject;
struct sysfs_ops { struct sysfs_ops {
int (*open)(struct driver_dir_entry *); ssize_t (*show)(struct kobject *, struct attribute *,char *, size_t, loff_t);
int (*close)(struct driver_dir_entry *); ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t, loff_t);
ssize_t (*show)(struct driver_dir_entry *, struct attribute *,char *, size_t, loff_t);
ssize_t (*store)(struct driver_dir_entry *,struct attribute *,const char *, size_t, loff_t);
}; };
struct driver_dir_entry { struct sysfs_dir {
char * name;
struct dentry * dentry; struct dentry * dentry;
mode_t mode;
struct sysfs_ops * ops; struct sysfs_ops * ops;
}; };
...@@ -32,20 +29,21 @@ struct attribute { ...@@ -32,20 +29,21 @@ struct attribute {
}; };
extern int extern int
sysfs_create_dir(struct driver_dir_entry *, struct driver_dir_entry *); sysfs_create_dir(struct kobject *);
extern void extern void
sysfs_remove_dir(struct driver_dir_entry * entry); sysfs_remove_dir(struct kobject *);
extern int extern int
sysfs_create_file(struct attribute * attr, sysfs_create_file(struct kobject *, struct attribute *);
struct driver_dir_entry * parent);
extern void
sysfs_remove_file(struct kobject *, struct attribute *);
extern int extern int
sysfs_create_symlink(struct driver_dir_entry * parent, sysfs_create_link(struct kobject * kobj, char * name, char * target);
char * name, char * target);
extern void extern void
sysfs_remove_file(struct driver_dir_entry *, const char * name); sysfs_remove_link(struct kobject *, char * name);
#endif /* _SYSFS_H_ */ #endif /* _SYSFS_H_ */
...@@ -9,10 +9,11 @@ ...@@ -9,10 +9,11 @@
L_TARGET := lib.a L_TARGET := lib.a
export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o \ export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o \
crc32.o rbtree.o radix-tree.o crc32.o rbtree.o radix-tree.o kobject.o
obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o \ obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o \
bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \
kobject.o
obj-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o obj-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
obj-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o obj-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
......
/*
* kobject.c - library routines for handling generic kernel objects
*/
#define DEBUG 1
#include <linux/kobject.h>
#include <linux/module.h>
#include <linux/stat.h>
/**
* kobject_init - initialize object.
* @kobj: object in question.
*/
void kobject_init(struct kobject * kobj)
{
atomic_set(&kobj->refcount,1);
INIT_LIST_HEAD(&kobj->entry);
}
/**
* kobject_register - register an object.
* @kobj: object in question.
*
* For now, fill in the replicated fields in the object's
* directory entry, and create a dir in sysfs.
* This stuff should go away in the future, as we move
* more implicit things to sysfs.
*/
int kobject_register(struct kobject * kobj)
{
pr_debug("kobject %s: registering\n",kobj->name);
if (kobj->parent)
kobject_get(kobj->parent);
return 0;
}
/**
* kobject_unregister - unlink an object.
* @kobj: object going away.
*
* The device has been told to be removed, but may
* not necessarily be disappearing from the kernel.
* So, we remove the directory and decrement the refcount
* that we set with kobject_register().
*
* Eventually (maybe now), the refcount will hit 0, and
* put_device() will clean the device up.
*/
void kobject_unregister(struct kobject * kobj)
{
pr_debug("kobject %s: unregistering\n",kobj->name);
kobject_put(kobj);
}
/**
* kobject_get - increment refcount for object.
* @kobj: object.
*/
struct kobject * kobject_get(struct kobject * kobj)
{
struct kobject * ret = kobj;
if (atomic_read(&kobj->refcount) > 0)
atomic_inc(&kobj->refcount);
else
ret = NULL;
return ret;
}
/**
* kobject_put - decrement refcount for object.
* @kobj: object.
*
* Decrement the refcount, and check if 0. If it is, then
* we're gonna need to clean it up, and decrement the refcount
* of its parent.
*/
void kobject_put(struct kobject * kobj)
{
struct kobject * parent = kobj->parent;
if (!atomic_dec_and_test(&kobj->refcount))
return;
pr_debug("kobject %s: cleaning up\n",kobj->name);
if (parent)
kobject_put(parent);
}
EXPORT_SYMBOL(kobject_init);
EXPORT_SYMBOL(kobject_register);
EXPORT_SYMBOL(kobject_unregister);
EXPORT_SYMBOL(kobject_get);
EXPORT_SYMBOL(kobject_put);
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