Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
ca01359a
Commit
ca01359a
authored
Nov 19, 2002
by
Patrick Mochel
Browse files
Options
Browse Files
Download
Plain Diff
merge
parents
fdea9fc9
0de8c962
Changes
14
Show whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
287 additions
and
117 deletions
+287
-117
Documentation/kobject.txt
Documentation/kobject.txt
+103
-22
drivers/base/base.h
drivers/base/base.h
+3
-0
drivers/base/bus.c
drivers/base/bus.c
+1
-1
drivers/base/core.c
drivers/base/core.c
+2
-2
drivers/base/cpu.c
drivers/base/cpu.c
+2
-2
drivers/base/driver.c
drivers/base/driver.c
+5
-1
drivers/base/fs/device.c
drivers/base/fs/device.c
+1
-1
drivers/base/hotplug.c
drivers/base/hotplug.c
+1
-1
drivers/base/intf.c
drivers/base/intf.c
+2
-2
drivers/base/power.c
drivers/base/power.c
+1
-1
drivers/base/sys.c
drivers/base/sys.c
+1
-1
fs/sysfs/inode.c
fs/sysfs/inode.c
+66
-24
include/linux/kobject.h
include/linux/kobject.h
+4
-0
lib/kobject.c
lib/kobject.c
+95
-59
No files found.
Documentation/kobject.txt
View file @
ca01359a
...
@@ -5,7 +5,9 @@ Patrick Mochel <mochel@osdl.org>
...
@@ -5,7 +5,9 @@ Patrick Mochel <mochel@osdl.org>
30 October 2002
30 October 2002
kobjects
1. kobjects
1.1 Description
struct kobject introduces a simple, intregral datatype and a simple
struct kobject introduces a simple, intregral datatype and a simple
set of semantics for operating on the device. kobjects are intended to
set of semantics for operating on the device. kobjects are intended to
...
@@ -13,8 +15,8 @@ be embedded in larger data structures and replace fields it
...
@@ -13,8 +15,8 @@ be embedded in larger data structures and replace fields it
duplicates. A set of library functions has been developed to assist in
duplicates. A set of library functions has been developed to assist in
the manipulation of kobjects.
the manipulation of kobjects.
struct kobject looks like this:
1.2 Defintion
struct kobject {
struct kobject {
char name[16];
char name[16];
...
@@ -26,21 +28,29 @@ struct kobject {
...
@@ -26,21 +28,29 @@ struct kobject {
};
};
void kobject_init(struct kobject *);
void kobject_init(struct kobject *);
int kobject_add(struct kobject *);
int kobject_register(struct kobject *);
int kobject_register(struct kobject *);
void kobject_del(struct kobject *);
void kobject_cleanup(struct kobject *);
void kobject_unregister(struct kobject *);
void kobject_unregister(struct kobject *);
struct kobject * kobject_get(struct kobject *);
struct kobject * kobject_get(struct kobject *);
void kobject_put(struct kobject *);
void kobject_put(struct kobject *);
subsystems
2. subsystems
2.1 Description
struct subsystem is introduced to describe a collection of objects of
struct subsystem is introduced to describe a collection of objects of
a certain type. subsystems are kobjects themselves, though they
a certain type. subsystems are kobjects themselves, though they
contain lists of kobjects that belong to that subsystem. Objects of a
contain lists of kobjects that belong to that subsystem. Objects of a
subsystem (the embedder objects in which kobjects live) are all of the
subsystem (the embedder objects in which kobjects live) are all of the
same type.
The interface looks like:
same type.
2.2 Definition
struct subsystem {
struct subsystem {
struct kobject kobj;
struct kobject kobj;
...
@@ -60,6 +70,95 @@ struct subsystem * subsys_get(struct subsystem * s);
...
@@ -60,6 +70,95 @@ struct subsystem * subsys_get(struct subsystem * s);
void subsys_put(struct subsystem * s);
void subsys_put(struct subsystem * s);
3. The Interface
The kobject API provides a symmeticral interface that may be used in
one of two ways: by using the default front-end registration
interface, or by directly using the backend helpers the registration
interface uses.
3.1 Default Usage
The default usage is to use kobjet_register() to add a device to the
object hierarchy, and kobject_unregister() to remove it.
kobject_register() will call kobject_init() and kobject_add()
consecutively. kobject_init() will initialize the object and increment
the reference count of the subsystem the object belongs to. It will
leave the reference count of the object at 1.
kobject_add() will insert it into the object hierarchy and create
a sysfs directory for the object. This will increment the reference
count of the object, leaving it at 2.
kobject_unregister() will call kobject_del() and kobject_put()
consecutively. kobject_del() will remove the object from the hierarchy
and the sysfs directory for the object. It will decrement the
reference count for the object. Assuming there are no other users of
the object, it will be left at 1.
kobject_put() will decrement the reference count of the object, and
when it reaches 0, call kobject_cleanup(). This will happen
immediately if there are no other users of the object.
kobject_cleanup() will call the subsystem's release() method
for the object, and decrement the subsystem's reference count.
Because kobject_unregister() calls kobject_put(), instead of
kobject_cleanup() directly, when an object is unregistered, the
pointer to the object is guaranteed to remain valid until the last
reference to the object has gone away.
Users of objects should call kobject_get() to obtain a reference to
the object that they are using. If the object passed to it is a valid
object (i.e. still present in the system), it will return a pointer to
the object. Otherwise, it will return NULL.
When users are done using an object, they should call kobject_put() to
decrement the reference count on the object. As explained above, when
the reference count for the object reaches 0, kobject_cleanup() will
be called for the object.
3.2 Backend Usage
Users of the kobject infrastructure may use the backend functions
directly. In order to maintain consistency and reduce confusion, users
of the interface should use only the front end registration-oriented
interface, or the backend helpers.
Using the backend helpers allows code to use the kobjects solely for
the reference counting and garbage collection mechanisms, and
optionally adding them to the object hierarchy or exporting them via
sysfs.
To take advantage of this side of the interface, users should call
kobject_init() to initialize the object. As stated above, this will
leave the reference count of the object at 1, and will enable the
subsystem to use the reference count of the object.
When the life of the object is ending, the kobject_put() should be
called to decrement the reference count of the object. Just like
above, this will call kobject_cleanup() when the reference count
reaches 0, and release() method of the object's subsystem will be
called.
During the lifetime of the object, kobject_add() and kobject_del() may
be called to add the object to the hierarchy and export it via
sysfs. kobject_del() must always be called if kobject_add() has
previously been called. Care should be taken to ensure kobject_del()
is called before the final kobject_put() is called, though not doing
so will not cause catastrophe, only confusion when reading the source
code. Fatal results are avoided by having kobject_add() increment the
reference count of the object, for kobject_del() to decrement.
3.3 Summary
Using either interface, users should obtain the same results. The
registration interface does the same actions as the backend interface,
though it guarantees that initialization and addition, and deletion
and cleanup, happen consecutively.
Familial Relations
Familial Relations
...
@@ -134,21 +233,3 @@ object that registers with them. A subsystem definition may contain a
...
@@ -134,21 +233,3 @@ object that registers with them. A subsystem definition may contain a
NULL-terminated array of attributes that will be exported when an
NULL-terminated array of attributes that will be exported when an
object is registered with the subsystem.
object is registered with the subsystem.
Reference Counting
All objects contain reference counts. All functions accessing objects
should increment the reference count until they are finished, and
decrement the reference count. When an object is initialized, it
receives a reference count of 1. When a device is unregistered, the
reference is decremented. When the reference counts reaches 0, the
subsystem's ->release() callback for that object type (remember
subsystems control only one type of device each) is called; and the
reference counts of the kobject's subsystem and parent are
decremented.
The ->release() callback is the opportunity for the subsystem to free
memory allocated for the object. It is the notification that
absolutely no one is using the structure any more (and can't acquire a
reference to it), so it is safe to free it.
drivers/base/base.h
View file @
ca01359a
...
@@ -19,6 +19,9 @@ extern void bus_remove_driver(struct device_driver *);
...
@@ -19,6 +19,9 @@ extern void bus_remove_driver(struct device_driver *);
extern
int
devclass_add_device
(
struct
device
*
);
extern
int
devclass_add_device
(
struct
device
*
);
extern
void
devclass_remove_device
(
struct
device
*
);
extern
void
devclass_remove_device
(
struct
device
*
);
extern
int
devclass_add_driver
(
struct
device_driver
*
);
extern
void
devclass_remove_driver
(
struct
device_driver
*
);
extern
int
interface_add
(
struct
device_class
*
,
struct
device
*
);
extern
int
interface_add
(
struct
device_class
*
,
struct
device
*
);
extern
void
interface_remove
(
struct
device_class
*
,
struct
device
*
);
extern
void
interface_remove
(
struct
device_class
*
,
struct
device
*
);
...
...
drivers/base/bus.c
View file @
ca01359a
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*/
*/
#
define DEBUG 0
#
undef DEBUG
#include <linux/device.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/module.h>
...
...
drivers/base/core.c
View file @
ca01359a
...
@@ -5,7 +5,7 @@
...
@@ -5,7 +5,7 @@
* 2002 Open Source Development Lab
* 2002 Open Source Development Lab
*/
*/
#
define DEBUG 0
#
undef DEBUG
#include <linux/device.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/err.h>
...
@@ -134,7 +134,7 @@ int device_add(struct device *dev)
...
@@ -134,7 +134,7 @@ int device_add(struct device *dev)
devclass_add_device
(
dev
);
devclass_add_device
(
dev
);
register_done:
register_done:
if
(
error
)
{
if
(
error
)
{
up
(
&
device_sem
);
down
(
&
device_sem
);
list_del_init
(
&
dev
->
g_list
);
list_del_init
(
&
dev
->
g_list
);
list_del_init
(
&
dev
->
node
);
list_del_init
(
&
dev
->
node
);
up
(
&
device_sem
);
up
(
&
device_sem
);
...
...
drivers/base/cpu.c
View file @
ca01359a
...
@@ -48,7 +48,7 @@ int __init register_cpu(struct cpu *cpu, int num, struct node *root)
...
@@ -48,7 +48,7 @@ int __init register_cpu(struct cpu *cpu, int num, struct node *root)
static
int
__init
register_cpu_type
(
void
)
static
int
__init
register_cpu_type
(
void
)
{
{
d
river_register
(
&
cpu_driver
);
d
evclass_register
(
&
cpu_devclass
);
return
d
evclass_register
(
&
cpu_devclass
);
return
d
river_register
(
&
cpu_driver
);
}
}
postcore_initcall
(
register_cpu_type
);
postcore_initcall
(
register_cpu_type
);
drivers/base/driver.c
View file @
ca01359a
...
@@ -3,7 +3,7 @@
...
@@ -3,7 +3,7 @@
*
*
*/
*/
#
define DEBUG 0
#
undef DEBUG
#include <linux/device.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/module.h>
...
@@ -118,6 +118,7 @@ int driver_register(struct device_driver * drv)
...
@@ -118,6 +118,7 @@ int driver_register(struct device_driver * drv)
INIT_LIST_HEAD
(
&
drv
->
devices
);
INIT_LIST_HEAD
(
&
drv
->
devices
);
drv
->
present
=
1
;
drv
->
present
=
1
;
bus_add_driver
(
drv
);
bus_add_driver
(
drv
);
devclass_add_driver
(
drv
);
put_driver
(
drv
);
put_driver
(
drv
);
return
0
;
return
0
;
}
}
...
@@ -128,6 +129,9 @@ void driver_unregister(struct device_driver * drv)
...
@@ -128,6 +129,9 @@ void driver_unregister(struct device_driver * drv)
drv
->
present
=
0
;
drv
->
present
=
0
;
spin_unlock
(
&
device_lock
);
spin_unlock
(
&
device_lock
);
pr_debug
(
"driver %s:%s: unregistering
\n
"
,
drv
->
bus
->
name
,
drv
->
name
);
pr_debug
(
"driver %s:%s: unregistering
\n
"
,
drv
->
bus
->
name
,
drv
->
name
);
bus_remove_driver
(
drv
);
devclass_remove_driver
(
drv
);
kobject_unregister
(
&
drv
->
kobj
);
put_driver
(
drv
);
put_driver
(
drv
);
}
}
...
...
drivers/base/fs/device.c
View file @
ca01359a
...
@@ -5,7 +5,7 @@
...
@@ -5,7 +5,7 @@
* 2002 Open Source Development Lab
* 2002 Open Source Development Lab
*/
*/
#
define DEBUG 0
#
undef DEBUG
#include <linux/device.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/module.h>
...
...
drivers/base/hotplug.c
View file @
ca01359a
...
@@ -10,7 +10,7 @@
...
@@ -10,7 +10,7 @@
*
*
*/
*/
#
define DEBUG 0
#
undef DEBUG
#include <linux/device.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/slab.h>
...
...
drivers/base/intf.c
View file @
ca01359a
...
@@ -2,7 +2,7 @@
...
@@ -2,7 +2,7 @@
* intf.c - class-specific interface management
* intf.c - class-specific interface management
*/
*/
#
define DEBUG 1
#
undef DEBUG
#include <linux/device.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/module.h>
...
@@ -37,7 +37,7 @@ int interface_register(struct device_interface * intf)
...
@@ -37,7 +37,7 @@ int interface_register(struct device_interface * intf)
struct
device_class
*
cls
=
intf
->
devclass
;
struct
device_class
*
cls
=
intf
->
devclass
;
if
(
cls
)
{
if
(
cls
)
{
pr_debug
(
"register interface '%s' with class '%s
\n
"
,
pr_debug
(
"register interface '%s' with class '%s
'
\n
"
,
intf
->
name
,
cls
->
name
);
intf
->
name
,
cls
->
name
);
kobject_init
(
&
intf
->
kobj
);
kobject_init
(
&
intf
->
kobj
);
strncpy
(
intf
->
kobj
.
name
,
intf
->
name
,
KOBJ_NAME_LEN
);
strncpy
(
intf
->
kobj
.
name
,
intf
->
name
,
KOBJ_NAME_LEN
);
...
...
drivers/base/power.c
View file @
ca01359a
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
*
*
*/
*/
#
define DEBUG 0
#
undef DEBUG
#include <linux/device.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/module.h>
...
...
drivers/base/sys.c
View file @
ca01359a
...
@@ -10,7 +10,7 @@
...
@@ -10,7 +10,7 @@
* add themselves as children of the system bus.
* add themselves as children of the system bus.
*/
*/
#
define DEBUG 1
#
undef DEBUG
#include <linux/device.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/err.h>
...
...
fs/sysfs/inode.c
View file @
ca01359a
...
@@ -23,6 +23,8 @@
...
@@ -23,6 +23,8 @@
* Please see Documentation/filesystems/sysfs.txt for more information.
* Please see Documentation/filesystems/sysfs.txt for more information.
*/
*/
#undef DEBUG
#include <linux/list.h>
#include <linux/list.h>
#include <linux/init.h>
#include <linux/init.h>
#include <linux/pagemap.h>
#include <linux/pagemap.h>
...
@@ -173,17 +175,11 @@ static ssize_t
...
@@ -173,17 +175,11 @@ 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
sysfs_ops
*
ops
=
NULL
;
struct
sysfs_ops
*
ops
=
file
->
private_data
;
struct
kobject
*
kobj
;
struct
kobject
*
kobj
=
file
->
f_dentry
->
d_parent
->
d_fsdata
;
unsigned
char
*
page
;
unsigned
char
*
page
;
ssize_t
retval
=
0
;
ssize_t
retval
=
0
;
kobj
=
file
->
f_dentry
->
d_parent
->
d_fsdata
;
if
(
kobj
&&
kobj
->
subsys
)
ops
=
kobj
->
subsys
->
sysfs_ops
;
if
(
!
ops
||
!
ops
->
show
)
return
0
;
if
(
count
>
PAGE_SIZE
)
if
(
count
>
PAGE_SIZE
)
count
=
PAGE_SIZE
;
count
=
PAGE_SIZE
;
...
@@ -234,16 +230,11 @@ static ssize_t
...
@@ -234,16 +230,11 @@ 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
sysfs_ops
*
ops
=
NULL
;
struct
sysfs_ops
*
ops
=
file
->
private_data
;
struct
kobject
*
kobj
;
struct
kobject
*
kobj
=
file
->
f_dentry
->
d_parent
->
d_fsdata
;
ssize_t
retval
=
0
;
ssize_t
retval
=
0
;
char
*
page
;
char
*
page
;
kobj
=
file
->
f_dentry
->
d_parent
->
d_fsdata
;
if
(
kobj
&&
kobj
->
subsys
)
ops
=
kobj
->
subsys
->
sysfs_ops
;
if
(
!
ops
||
!
ops
->
store
)
return
-
EINVAL
;
page
=
(
char
*
)
__get_free_page
(
GFP_KERNEL
);
page
=
(
char
*
)
__get_free_page
(
GFP_KERNEL
);
if
(
!
page
)
if
(
!
page
)
...
@@ -275,21 +266,72 @@ sysfs_write_file(struct file *file, const char *buf, size_t count, loff_t *ppos)
...
@@ -275,21 +266,72 @@ sysfs_write_file(struct file *file, const char *buf, size_t count, loff_t *ppos)
return
retval
;
return
retval
;
}
}
static
int
sysfs_open_file
(
struct
inode
*
inode
,
struct
file
*
filp
)
static
int
check_perm
(
struct
inode
*
inode
,
struct
file
*
file
)
{
{
struct
kobject
*
kobj
;
struct
kobject
*
kobj
=
kobject_get
(
file
->
f_dentry
->
d_parent
->
d_fsdata
);
struct
attribute
*
attr
=
file
->
f_dentry
->
d_fsdata
;
struct
sysfs_ops
*
ops
=
NULL
;
int
error
=
0
;
int
error
=
0
;
kobj
=
filp
->
f_dentry
->
d_parent
->
d_fsdata
;
if
(
!
kobj
||
!
attr
)
if
((
kobj
=
kobject_get
(
kobj
)))
{
goto
Einval
;
struct
attribute
*
attr
=
filp
->
f_dentry
->
d_fsdata
;
if
(
!
attr
)
if
(
kobj
->
subsys
)
error
=
-
EINVAL
;
ops
=
kobj
->
subsys
->
sysfs_ops
;
}
else
/* No sysfs operations, either from having no subsystem,
* or the subsystem have no operations.
*/
if
(
!
ops
)
goto
Eaccess
;
/* File needs write support.
* The inode's perms must say it's ok,
* and we must have a store method.
*/
if
(
file
->
f_mode
&
FMODE_WRITE
)
{
if
(
!
(
inode
->
i_mode
&
S_IWUGO
))
goto
Eperm
;
if
(
!
ops
->
store
)
goto
Eaccess
;
}
/* File needs read support.
* The inode's perms must say it's ok, and we there
* must be a show method for it.
*/
if
(
file
->
f_mode
&
FMODE_READ
)
{
if
(
!
(
inode
->
i_mode
&
S_IRUGO
))
goto
Eperm
;
if
(
!
ops
->
show
)
goto
Eaccess
;
}
/* No error? Great, store the ops in file->private_data
* for easy access in the read/write functions.
*/
file
->
private_data
=
ops
;
goto
Done
;
Einval:
error
=
-
EINVAL
;
error
=
-
EINVAL
;
goto
Done
;
Eaccess:
error
=
-
EACCES
;
goto
Done
;
Eperm:
error
=
-
EPERM
;
Done:
return
error
;
return
error
;
}
}
static
int
sysfs_open_file
(
struct
inode
*
inode
,
struct
file
*
filp
)
{
return
check_perm
(
inode
,
filp
);
}
static
int
sysfs_release
(
struct
inode
*
inode
,
struct
file
*
filp
)
static
int
sysfs_release
(
struct
inode
*
inode
,
struct
file
*
filp
)
{
{
struct
kobject
*
kobj
=
filp
->
f_dentry
->
d_parent
->
d_fsdata
;
struct
kobject
*
kobj
=
filp
->
f_dentry
->
d_parent
->
d_fsdata
;
...
...
include/linux/kobject.h
View file @
ca01359a
...
@@ -24,6 +24,10 @@ struct kobject {
...
@@ -24,6 +24,10 @@ struct kobject {
};
};
extern
void
kobject_init
(
struct
kobject
*
);
extern
void
kobject_init
(
struct
kobject
*
);
extern
void
kobject_cleanup
(
struct
kobject
*
);
extern
int
kobject_add
(
struct
kobject
*
);
extern
void
kobject_del
(
struct
kobject
*
);
extern
int
kobject_register
(
struct
kobject
*
);
extern
int
kobject_register
(
struct
kobject
*
);
extern
void
kobject_unregister
(
struct
kobject
*
);
extern
void
kobject_unregister
(
struct
kobject
*
);
...
...
lib/kobject.c
View file @
ca01359a
...
@@ -2,15 +2,17 @@
...
@@ -2,15 +2,17 @@
* kobject.c - library routines for handling generic kernel objects
* kobject.c - library routines for handling generic kernel objects
*/
*/
#
define DEBUG 0
#
undef DEBUG
#include <linux/kobject.h>
#include <linux/kobject.h>
#include <linux/string.h>
#include <linux/string.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/stat.h>
#include <linux/stat.h>
static
spinlock_t
kobj_lock
=
SPIN_LOCK_UNLOCKED
;
/**
/**
*
kobject_
populate_dir - populate directory with attributes.
* populate_dir - populate directory with attributes.
* @kobj: object we're working on.
* @kobj: object we're working on.
*
*
* Most subsystems have a set of default attributes that
* Most subsystems have a set of default attributes that
...
@@ -21,7 +23,7 @@
...
@@ -21,7 +23,7 @@
*
*
*/
*/
static
int
kobject_
populate_dir
(
struct
kobject
*
kobj
)
static
int
populate_dir
(
struct
kobject
*
kobj
)
{
{
struct
subsystem
*
s
=
kobj
->
subsys
;
struct
subsystem
*
s
=
kobj
->
subsys
;
struct
attribute
*
attr
;
struct
attribute
*
attr
;
...
@@ -37,6 +39,20 @@ static int kobject_populate_dir(struct kobject * kobj)
...
@@ -37,6 +39,20 @@ static int kobject_populate_dir(struct kobject * kobj)
return
error
;
return
error
;
}
}
static
int
create_dir
(
struct
kobject
*
kobj
)
{
int
error
=
0
;
if
(
strlen
(
kobj
->
name
))
{
error
=
sysfs_create_dir
(
kobj
);
if
(
!
error
)
{
if
((
error
=
populate_dir
(
kobj
)))
sysfs_remove_dir
(
kobj
);
}
}
return
error
;
}
/**
/**
* kobject_init - initialize object.
* kobject_init - initialize object.
* @kobj: object in question.
* @kobj: object in question.
...
@@ -46,70 +62,88 @@ void kobject_init(struct kobject * kobj)
...
@@ -46,70 +62,88 @@ void kobject_init(struct kobject * kobj)
{
{
atomic_set
(
&
kobj
->
refcount
,
1
);
atomic_set
(
&
kobj
->
refcount
,
1
);
INIT_LIST_HEAD
(
&
kobj
->
entry
);
INIT_LIST_HEAD
(
&
kobj
->
entry
);
kobj
->
subsys
=
subsys_get
(
kobj
->
subsys
);
}
}
/**
/**
* kobject_register - register an object.
* kobject_add - add an object to the hierarchy.
* @kobj: object in question.
* @kobj: object.
*
* 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
)
int
kobject_
add
(
struct
kobject
*
kobj
)
{
{
int
error
=
0
;
int
error
=
0
;
struct
subsystem
*
s
=
subsys_get
(
kobj
->
subsys
)
;
struct
subsystem
*
s
=
kobj
->
subsys
;
struct
kobject
*
parent
=
kobject_get
(
kobj
->
parent
);
struct
kobject
*
parent
=
kobject_get
(
kobj
->
parent
);
pr_debug
(
"kobject %s: registering
\n
"
,
kobj
->
name
);
if
(
!
(
kobj
=
kobject_get
(
kobj
)))
if
(
parent
)
return
-
ENOENT
;
pr_debug
(
" parent is %s
\n
"
,
parent
->
name
);
pr_debug
(
"kobject %s: registering. parent: %s, subsys: %s
\n
"
,
kobj
->
name
,
parent
?
parent
->
name
:
"<NULL>"
,
kobj
->
subsys
?
kobj
->
subsys
->
kobj
.
name
:
"<NULL>"
);
if
(
s
)
{
if
(
s
)
{
down_write
(
&
s
->
rwsem
);
down_write
(
&
s
->
rwsem
);
if
(
parent
)
if
(
parent
)
list_add_tail
(
&
kobj
->
entry
,
&
parent
->
entry
);
list_add_tail
(
&
kobj
->
entry
,
&
parent
->
entry
);
else
{
else
{
list_add_tail
(
&
kobj
->
entry
,
&
s
->
list
);
list_add_tail
(
&
kobj
->
entry
,
&
s
->
list
);
kobj
->
parent
=
&
s
->
kobj
;
kobj
->
parent
=
kobject_get
(
&
s
->
kobj
)
;
}
}
up_write
(
&
s
->
rwsem
);
up_write
(
&
s
->
rwsem
);
}
}
if
(
strlen
(
kobj
->
name
))
{
error
=
create_dir
(
kobj
);
error
=
sysfs_create_dir
(
kobj
);
if
(
error
&&
kobj
->
parent
)
if
(
!
error
)
{
kobject_put
(
kobj
->
parent
);
error
=
kobject_populate_dir
(
kobj
);
return
error
;
}
/**
* kobject_register - initialize and add an object.
* @kobj: object in question.
*/
int
kobject_register
(
struct
kobject
*
kobj
)
{
int
error
=
0
;
if
(
kobj
)
{
kobject_init
(
kobj
);
error
=
kobject_add
(
kobj
);
if
(
error
)
if
(
error
)
sysfs_remove_dir
(
kobj
);
kobject_cleanup
(
kobj
);
}
}
else
}
error
=
-
EINVAL
;
return
error
;
return
error
;
}
}
/**
/**
* kobject_unregister - unlink an object.
* kobject_del - unlink kobject from hierarchy.
* @kobj: object going away.
* @kobj: object.
*
* 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
)
void
kobject_
del
(
struct
kobject
*
kobj
)
{
{
pr_debug
(
"kobject %s: unregistering
\n
"
,
kobj
->
name
);
sysfs_remove_dir
(
kobj
);
sysfs_remove_dir
(
kobj
);
if
(
kobj
->
subsys
)
{
if
(
kobj
->
subsys
)
{
down_write
(
&
kobj
->
subsys
->
rwsem
);
down_write
(
&
kobj
->
subsys
->
rwsem
);
list_del_init
(
&
kobj
->
entry
);
list_del_init
(
&
kobj
->
entry
);
up_write
(
&
kobj
->
subsys
->
rwsem
);
up_write
(
&
kobj
->
subsys
->
rwsem
);
}
}
if
(
kobj
->
parent
)
kobject_put
(
kobj
->
parent
);
kobject_put
(
kobj
);
}
/**
* kobject_unregister - remove object from hierarchy and decrement refcount.
* @kobj: object going away.
*/
void
kobject_unregister
(
struct
kobject
*
kobj
)
{
pr_debug
(
"kobject %s: unregistering
\n
"
,
kobj
->
name
);
kobject_del
(
kobj
);
kobject_put
(
kobj
);
kobject_put
(
kobj
);
}
}
...
@@ -121,45 +155,48 @@ void kobject_unregister(struct kobject * kobj)
...
@@ -121,45 +155,48 @@ void kobject_unregister(struct kobject * kobj)
struct
kobject
*
kobject_get
(
struct
kobject
*
kobj
)
struct
kobject
*
kobject_get
(
struct
kobject
*
kobj
)
{
{
struct
kobject
*
ret
=
kobj
;
struct
kobject
*
ret
=
kobj
;
spin_lock
(
&
kobj_lock
);
if
(
kobj
&&
atomic_read
(
&
kobj
->
refcount
)
>
0
)
if
(
kobj
&&
atomic_read
(
&
kobj
->
refcount
)
>
0
)
atomic_inc
(
&
kobj
->
refcount
);
atomic_inc
(
&
kobj
->
refcount
);
else
else
ret
=
NULL
;
ret
=
NULL
;
spin_unlock
(
&
kobj_lock
);
return
ret
;
return
ret
;
}
}
/**
/**
* kobject_
put - decrement refcount for object.
* kobject_
cleanup - free kobject resources.
* @kobj: 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.
*
* @kobj->parent could point to its subsystem, which we also
* want to decrement the reference count for. We always dec
* the refcount for the parent, but only do so for the subsystem
* if it points to a different place than the parent.
*/
*/
void
kobject_
put
(
struct
kobject
*
kobj
)
void
kobject_
cleanup
(
struct
kobject
*
kobj
)
{
{
struct
kobject
*
parent
=
kobj
->
parent
;
struct
subsystem
*
s
=
kobj
->
subsys
;
struct
subsystem
*
s
=
kobj
->
subsys
;
if
(
!
atomic_dec_and_test
(
&
kobj
->
refcount
))
return
;
pr_debug
(
"kobject %s: cleaning up
\n
"
,
kobj
->
name
);
pr_debug
(
"kobject %s: cleaning up
\n
"
,
kobj
->
name
);
if
(
s
)
{
if
(
s
)
{
down_write
(
&
s
->
rwsem
);
list_del_init
(
&
kobj
->
entry
);
if
(
s
->
release
)
if
(
s
->
release
)
s
->
release
(
kobj
);
s
->
release
(
kobj
);
if
(
&
s
->
kobj
!=
parent
)
up_write
(
&
s
->
rwsem
);
subsys_put
(
s
);
subsys_put
(
s
);
}
}
}
if
(
parent
)
/**
kobject_put
(
parent
);
* kobject_put - decrement refcount for object.
* @kobj: object.
*
* Decrement the refcount, and if 0, call kobject_cleanup().
*/
void
kobject_put
(
struct
kobject
*
kobj
)
{
if
(
!
atomic_dec_and_lock
(
&
kobj
->
refcount
,
&
kobj_lock
))
return
;
spin_unlock
(
&
kobj_lock
);
kobject_cleanup
(
kobj
);
}
}
...
@@ -180,9 +217,8 @@ int subsystem_register(struct subsystem * s)
...
@@ -180,9 +217,8 @@ int subsystem_register(struct subsystem * s)
subsystem_init
(
s
);
subsystem_init
(
s
);
if
(
s
->
parent
)
if
(
s
->
parent
)
s
->
kobj
.
parent
=
&
s
->
parent
->
kobj
;
s
->
kobj
.
parent
=
&
s
->
parent
->
kobj
;
pr_debug
(
"subsystem %s: registering
\n
"
,
s
->
kobj
.
name
);
pr_debug
(
"subsystem %s: registering, parent: %s
\n
"
,
if
(
s
->
parent
)
s
->
kobj
.
name
,
s
->
parent
?
s
->
parent
->
kobj
.
name
:
"<none>"
);
pr_debug
(
" parent is %s
\n
"
,
s
->
parent
->
kobj
.
name
);
return
kobject_register
(
&
s
->
kobj
);
return
kobject_register
(
&
s
->
kobj
);
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment