diff --git a/Documentation/kobject.txt b/Documentation/kobject.txt index ca86a885ad8f71c6f98647debd50bf293b33de47..bf3256e04027686430823fe32333fabf968a3de4 100644 --- a/Documentation/kobject.txt +++ b/Documentation/kobject.txt @@ -1,289 +1,386 @@ -The kobject Infrastructure +Everything you never wanted to know about kobjects, ksets, and ktypes -Patrick Mochel <mochel@osdl.org> +Greg Kroah-Hartman <gregkh@suse.de> -Updated: 3 June 2003 +Based on an original article by Jon Corbet for lwn.net written October 1, +2003 and located at http://lwn.net/Articles/51437/ +Last updated December 19, 2007 -Copyright (c) 2003 Patrick Mochel -Copyright (c) 2003 Open Source Development Labs +Part of the difficulty in understanding the driver model - and the kobject +abstraction upon which it is built - is that there is no obvious starting +place. Dealing with kobjects requires understanding a few different types, +all of which make reference to each other. In an attempt to make things +easier, we'll take a multi-pass approach, starting with vague terms and +adding detail as we go. To that end, here are some quick definitions of +some terms we will be working with. -0. Introduction + - A kobject is an object of type struct kobject. Kobjects have a name + and a reference count. A kobject also has a parent pointer (allowing + objects to be arranged into hierarchies), a specific type, and, + usually, a representation in the sysfs virtual filesystem. -The kobject infrastructure performs basic object management that larger -data structures and subsystems can leverage, rather than reimplement -similar functionality. This functionality primarily concerns: + Kobjects are generally not interesting on their own; instead, they are + usually embedded within some other structure which contains the stuff + the code is really interested in. -- Object reference counting. -- Maintaining lists (sets) of objects. -- Object set locking. -- Userspace representation. + No structure should EVER have more than one kobject embedded within it. + If it does, the reference counting for the object is sure to be messed + up and incorrect, and your code will be buggy. So do not do this. -The infrastructure consists of a number of object types to support -this functionality. Their programming interfaces are described below -in detail, and briefly here: + - A ktype is the type of object that embeds a kobject. Every structure + that embeds a kobject needs a corresponding ktype. The ktype controls + what happens to the kobject when it is created and destroyed. -- kobjects a simple object. -- kset a set of objects of a certain type. -- ktype a set of helpers for objects of a common type. + - A kset is a group of kobjects. These kobjects can be of the same ktype + or belong to different ktypes. The kset is the basic container type for + collections of kobjects. Ksets contain their own kobjects, but you can + safely ignore that implementation detail as the kset core code handles + this kobject automatically. + When you see a sysfs directory full of other directories, generally each + of those directories corresponds to a kobject in the same kset. -The kobject infrastructure maintains a close relationship with the -sysfs filesystem. Each kobject that is registered with the kobject -core receives a directory in sysfs. Attributes about the kobject can -then be exported. Please see Documentation/filesystems/sysfs.txt for -more information. +We'll look at how to create and manipulate all of these types. A bottom-up +approach will be taken, so we'll go back to kobjects. -The kobject infrastructure provides a flexible programming interface, -and allows kobjects and ksets to be used without being registered -(i.e. with no sysfs representation). This is also described later. +Embedding kobjects -1. kobjects +It is rare for kernel code to create a standalone kobject, with one major +exception explained below. Instead, kobjects are used to control access to +a larger, domain-specific object. To this end, kobjects will be found +embedded in other structures. If you are used to thinking of things in +object-oriented terms, kobjects can be seen as a top-level, abstract class +from which other classes are derived. A kobject implements a set of +capabilities which are not particularly useful by themselves, but which are +nice to have in other objects. The C language does not allow for the +direct expression of inheritance, so other techniques - such as structure +embedding - must be used. -1.1 Description +So, for example, the UIO code has a structure that defines the memory +region associated with a uio device: +struct uio_mem { + struct kobject kobj; + unsigned long addr; + unsigned long size; + int memtype; + void __iomem *internal_addr; +}; -struct kobject is a simple data type that provides a foundation for -more complex object types. It provides a set of basic fields that -almost all complex data types share. kobjects are intended to be -embedded in larger data structures and replace fields they duplicate. +If you have a struct uio_mem structure, finding its embedded kobject is +just a matter of using the kobj member. Code that works with kobjects will +often have the opposite problem, however: given a struct kobject pointer, +what is the pointer to the containing structure? You must avoid tricks +(such as assuming that the kobject is at the beginning of the structure) +and, instead, use the container_of() macro, found in <linux/kernel.h>: -1.2 Definition + container_of(pointer, type, member) -struct kobject { - const char * k_name; - struct kref kref; - struct list_head entry; - struct kobject * parent; - struct kset * kset; - struct kobj_type * ktype; - struct sysfs_dirent * sd; - wait_queue_head_t poll; -}; +where pointer is the pointer to the embedded kobject, type is the type of +the containing structure, and member is the name of the structure field to +which pointer points. The return value from container_of() is a pointer to +the given type. So, for example, a pointer "kp" to a struct kobject +embedded within a struct uio_mem could be converted to a pointer to the +containing uio_mem structure with: -void kobject_init(struct kobject *); -int kobject_add(struct kobject *); -int kobject_register(struct kobject *); + struct uio_mem *u_mem = container_of(kp, struct uio_mem, kobj); -void kobject_del(struct kobject *); -void kobject_unregister(struct kobject *); +Programmers often define a simple macro for "back-casting" kobject pointers +to the containing type. -struct kobject * kobject_get(struct kobject *); -void kobject_put(struct kobject *); +Initialization of kobjects -1.3 kobject Programming Interface +Code which creates a kobject must, of course, initialize that object. Some +of the internal fields are setup with a (mandatory) call to kobject_init(): -kobjects may be dynamically added and removed from the kobject core -using kobject_register() and kobject_unregister(). Registration -includes inserting the kobject in the list of its dominant kset and -creating a directory for it in sysfs. + void kobject_init(struct kobject *kobj, struct kobj_type *ktype); -Alternatively, one may use a kobject without adding it to its kset's list -or exporting it via sysfs, by simply calling kobject_init(). An -initialized kobject may later be added to the object hierarchy by -calling kobject_add(). An initialized kobject may be used for -reference counting. +The ktype is required for a kobject to be created properly, as every kobject +must have an associated kobj_type. After calling kobject_init(), to +register the kobject with sysfs, the function kobject_add() must be called: -Note: calling kobject_init() then kobject_add() is functionally -equivalent to calling kobject_register(). + int kobject_add(struct kobject *kobj, struct kobject *parent, const char *fmt, ...); -When a kobject is unregistered, it is removed from its kset's list, -removed from the sysfs filesystem, and its reference count is decremented. -List and sysfs removal happen in kobject_del(), and may be called -manually. kobject_put() decrements the reference count, and may also -be called manually. +This sets up the parent of the kobject and the name for the kobject +properly. If the kobject is to be associated with a specific kset, +kobj->kset must be assigned before calling kobject_add(). If a kset is +associated with a kobject, then the parent for the kobject can be set to +NULL in the call to kobject_add() and then the kobject's parent will be the +kset itself. -A kobject's reference count may be incremented with kobject_get(), -which returns a valid reference to a kobject; and decremented with -kobject_put(). An object's reference count may only be incremented if -it is already positive. +As the name of the kobject is set when it is added to the kernel, the name +of the kobject should never be manipulated directly. If you must change +the name of the kobject, call kobject_rename(): -When a kobject's reference count reaches 0, the method struct -kobj_type::release() (which the kobject's kset points to) is called. -This allows any memory allocated for the object to be freed. + int kobject_rename(struct kobject *kobj, const char *new_name); +There is a function called kobject_set_name() but that is legacy cruft and +is being removed. If your code needs to call this function, it is +incorrect and needs to be fixed. -NOTE!!! +To properly access the name of the kobject, use the function +kobject_name(): -It is _imperative_ that you supply a destructor for dynamically -allocated kobjects to free them if you are using kobject reference -counts. The reference count controls the lifetime of the object. -If it goes to 0, then it is assumed that the object will -be freed and cannot be used. + const char *kobject_name(const struct kobject * kobj); -More importantly, you must free the object there, and not immediately -after an unregister call. If someone else is referencing the object -(e.g. through a sysfs file), they will obtain a reference to the -object, assume it's valid and operate on it. If the object is -unregistered and freed in the meantime, the operation will then -reference freed memory and go boom. +There is a helper function to both initialize and add the kobject to the +kernel at the same time, called supprisingly enough kobject_init_and_add(): -This can be prevented, in the simplest case, by defining a release -method and freeing the object from there only. Note that this will not -secure reference count/object management models that use a dual -reference count or do other wacky things with the reference count -(like the networking layer). + int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype, + struct kobject *parent, const char *fmt, ...); +The arguments are the same as the individual kobject_init() and +kobject_add() functions described above. -1.4 sysfs -Each kobject receives a directory in sysfs. This directory is created -under the kobject's parent directory. +Uevents -If a kobject does not have a parent when it is registered, its parent -becomes its dominant kset. +After a kobject has been registered with the kobject core, you need to +announce to the world that it has been created. This can be done with a +call to kobject_uevent(): -If a kobject does not have a parent nor a dominant kset, its directory -is created at the top-level of the sysfs partition. + int kobject_uevent(struct kobject *kobj, enum kobject_action action); +Use the KOBJ_ADD action for when the kobject is first added to the kernel. +This should be done only after any attributes or children of the kobject +have been initialized properly, as userspace will instantly start to look +for them when this call happens. +When the kobject is removed from the kernel (details on how to do that is +below), the uevent for KOBJ_REMOVE will be automatically created by the +kobject core, so the caller does not have to worry about doing that by +hand. -2. ksets -2.1 Description +Reference counts -A kset is a set of kobjects that are embedded in the same type. +One of the key functions of a kobject is to serve as a reference counter +for the object in which it is embedded. As long as references to the object +exist, the object (and the code which supports it) must continue to exist. +The low-level functions for manipulating a kobject's reference counts are: + struct kobject *kobject_get(struct kobject *kobj); + void kobject_put(struct kobject *kobj); -struct kset { - struct kobj_type * ktype; - struct list_head list; - struct kobject kobj; - struct kset_uevent_ops * uevent_ops; -}; +A successful call to kobject_get() will increment the kobject's reference +counter and return the pointer to the kobject. +When a reference is released, the call to kobject_put() will decrement the +reference count and, possibly, free the object. Note that kobject_init() +sets the reference count to one, so the code which sets up the kobject will +need to do a kobject_put() eventually to release that reference. -void kset_init(struct kset * k); -int kset_add(struct kset * k); -int kset_register(struct kset * k); -void kset_unregister(struct kset * k); +Because kobjects are dynamic, they must not be declared statically or on +the stack, but instead, always allocated dynamically. Future versions of +the kernel will contain a run-time check for kobjects that are created +statically and will warn the developer of this improper usage. -struct kset * kset_get(struct kset * k); -void kset_put(struct kset * k); +If all that you want to use a kobject for is to provide a reference counter +for your structure, please use the struct kref instead; a kobject would be +overkill. For more information on how to use struct kref, please see the +file Documentation/kref.txt in the Linux kernel source tree. -struct kobject * kset_find_obj(struct kset *, char *); +Creating "simple" kobjects -The type that the kobjects are embedded in is described by the ktype -pointer. +Sometimes all that a developer wants is a way to create a simple directory +in the sysfs hierarchy, and not have to mess with the whole complication of +ksets, show and store functions, and other details. This is the one +exception where a single kobject should be created. To create such an +entry, use the function: -A kset contains a kobject itself, meaning that it may be registered in -the kobject hierarchy and exported via sysfs. More importantly, the -kset may be embedded in a larger data type, and may be part of another -kset (of that object type). + struct kobject *kobject_create_and_add(char *name, struct kobject *parent); -For example, a block device is an object (struct gendisk) that is -contained in a set of block devices. It may also contain a set of -partitions (struct hd_struct) that have been found on the device. The -following code snippet illustrates how to express this properly. +This function will create a kobject and place it in sysfs in the location +underneath the specified parent kobject. To create simple attributes +associated with this kobject, use: - struct gendisk * disk; - ... - disk->kset.kobj.kset = &block_kset; - disk->kset.ktype = &partition_ktype; - kset_register(&disk->kset); + int sysfs_create_file(struct kobject *kobj, struct attribute *attr); +or + int sysfs_create_group(struct kobject *kobj, struct attribute_group *grp); -- The kset that the disk's embedded object belongs to is the - block_kset, and is pointed to by disk->kset.kobj.kset. +Both types of attributes used here, with a kobject that has been created +with the kobject_create_and_add(), can be of type kobj_attribute, so no +special custom attribute is needed to be created. -- The type of objects on the disk's _subordinate_ list are partitions, - and is set in disk->kset.ktype. +See the example module, samples/kobject/kobject-example.c for an +implementation of a simple kobject and attributes. -- The kset is then registered, which handles initializing and adding - the embedded kobject to the hierarchy. -2.2 kset Programming Interface +ktypes and release methods -All kset functions, except kset_find_obj(), eventually forward the -calls to their embedded kobjects after performing kset-specific -operations. ksets offer a similar programming model to kobjects: they -may be used after they are initialized, without registering them in -the hierarchy. +One important thing still missing from the discussion is what happens to a +kobject when its reference count reaches zero. The code which created the +kobject generally does not know when that will happen; if it did, there +would be little point in using a kobject in the first place. Even +predictable object lifecycles become more complicated when sysfs is brought +in as other portions of the kernel can get a reference on any kobject that +is registered in the system. -kset_find_obj() may be used to locate a kobject with a particular -name. The kobject, if found, is returned. +The end result is that a structure protected by a kobject cannot be freed +before its reference count goes to zero. The reference count is not under +the direct control of the code which created the kobject. So that code must +be notified asynchronously whenever the last reference to one of its +kobjects goes away. -There are also some helper functions which names point to the formerly -existing "struct subsystem", whose functions have been taken over by -ksets. +Once you registered your kobject via kobject_add(), you must never use +kfree() to free it directly. The only safe way is to use kobject_put(). It +is good practice to always use kobject_put() after kobject_init() to avoid +errors creeping in. +This notification is done through a kobject's release() method. Usually +such a method has a form like: -decl_subsys(name,type,uevent_ops) + void my_object_release(struct kobject *kobj) + { + struct my_object *mine = container_of(kobj, struct my_object, kobj); -Declares a kset named '<name>_subsys' of type <type> with -uevent_ops <uevent_ops>. For example, + /* Perform any additional cleanup on this object, then... */ + kfree(mine); + } -decl_subsys(devices, &ktype_device, &device_uevent_ops); +One important point cannot be overstated: every kobject must have a +release() method, and the kobject must persist (in a consistent state) +until that method is called. If these constraints are not met, the code is +flawed. Note that the kernel will warn you if you forget to provide a +release() method. Do not try to get rid of this warning by providing an +"empty" release function; you will be mocked mercilessly by the kobject +maintainer if you attempt this. -is equivalent to doing: +Note, the name of the kobject is available in the release function, but it +must NOT be changed within this callback. Otherwise there will be a memory +leak in the kobject core, which makes people unhappy. -struct kset devices_subsys = { - .ktype = &ktype_devices, - .uevent_ops = &device_uevent_ops, -}; -kobject_set_name(&devices_subsys, name); +Interestingly, the release() method is not stored in the kobject itself; +instead, it is associated with the ktype. So let us introduce struct +kobj_type: + + struct kobj_type { + void (*release)(struct kobject *); + struct sysfs_ops *sysfs_ops; + struct attribute **default_attrs; + }; -The objects that are registered with a subsystem that use the -subsystem's default list must have their kset ptr set properly. These -objects may have embedded kobjects or ksets. The -following helper makes setting the kset easier: +This structure is used to describe a particular type of kobject (or, more +correctly, of containing object). Every kobject needs to have an associated +kobj_type structure; a pointer to that structure must be specified when you +call kobject_init() or kobject_init_and_add(). +The release field in struct kobj_type is, of course, a pointer to the +release() method for this type of kobject. The other two fields (sysfs_ops +and default_attrs) control how objects of this type are represented in +sysfs; they are beyond the scope of this document. -kobj_set_kset_s(obj,subsys) +The default_attrs pointer is a list of default attributes that will be +automatically created for any kobject that is registered with this ktype. -- Assumes that obj->kobj exists, and is a struct kobject. -- Sets the kset of that kobject to the kset <subsys>. -int subsystem_register(struct kset *s); -void subsystem_unregister(struct kset *s); +ksets -These are just wrappers around the respective kset_* functions. +A kset is merely a collection of kobjects that want to be associated with +each other. There is no restriction that they be of the same ktype, but be +very careful if they are not. -2.3 sysfs +A kset serves these functions: -ksets are represented in sysfs when their embedded kobjects are -registered. They follow the same rules of parenting, with one -exception. If a kset does not have a parent, nor is its embedded -kobject part of another kset, the kset's parent becomes its dominant -subsystem. + - It serves as a bag containing a group of objects. A kset can be used by + the kernel to track "all block devices" or "all PCI device drivers." -If the kset does not have a parent, its directory is created at the -sysfs root. This should only happen when the kset registered is -embedded in a subsystem itself. + - A kset is also a subdirectory in sysfs, where the associated kobjects + with the kset can show up. Every kset contains a kobject which can be + set up to be the parent of other kobjects; the top-level directories of + the sysfs hierarchy are constructed in this way. + - Ksets can support the "hotplugging" of kobjects and influence how + uevent events are reported to user space. -3. struct ktype +In object-oriented terms, "kset" is the top-level container class; ksets +contain their own kobject, but that kobject is managed by the kset code and +should not be manipulated by any other user. -3.1. Description +A kset keeps its children in a standard kernel linked list. Kobjects point +back to their containing kset via their kset field. In almost all cases, +the kobjects belonging to a ket have that kset (or, strictly, its embedded +kobject) in their parent. -struct kobj_type { - void (*release)(struct kobject *); - struct sysfs_ops * sysfs_ops; - struct attribute ** default_attrs; +As a kset contains a kobject within it, it should always be dynamically +created and never declared statically or on the stack. To create a new +kset use: + struct kset *kset_create_and_add(const char *name, + struct kset_uevent_ops *u, + struct kobject *parent); + +When you are finished with the kset, call: + void kset_unregister(struct kset *kset); +to destroy it. + +An example of using a kset can be seen in the +samples/kobject/kset-example.c file in the kernel tree. + +If a kset wishes to control the uevent operations of the kobjects +associated with it, it can use the struct kset_uevent_ops to handle it: + +struct kset_uevent_ops { + int (*filter)(struct kset *kset, struct kobject *kobj); + const char *(*name)(struct kset *kset, struct kobject *kobj); + int (*uevent)(struct kset *kset, struct kobject *kobj, + struct kobj_uevent_env *env); }; -Object types require specific functions for converting between the -generic object and the more complex type. struct kobj_type provides -the object-specific fields, which include: +The filter function allows a kset to prevent a uevent from being emitted to +userspace for a specific kobject. If the function returns 0, the uevent +will not be emitted. + +The name function will be called to override the default name of the kset +that the uevent sends to userspace. By default, the name will be the same +as the kset itself, but this function, if present, can override that name. + +The uevent function will be called when the uevent is about to be sent to +userspace to allow more environment variables to be added to the uevent. + +One might ask how, exactly, a kobject is added to a kset, given that no +functions which perform that function have been presented. The answer is +that this task is handled by kobject_add(). When a kobject is passed to +kobject_add(), its kset member should point to the kset to which the +kobject will belong. kobject_add() will handle the rest. + +If the kobject belonging to a kset has no parent kobject set, it will be +added to the kset's directory. Not all members of a kset do necessarily +live in the kset directory. If an explicit parent kobject is assigned +before the kobject is added, the kobject is registered with the kset, but +added below the parent kobject. + + +Kobject removal -- release: Called when the kobject's reference count reaches 0. This - should convert the object to the more complex type and free it. +After a kobject has been registered with the kobject core successfully, it +must be cleaned up when the code is finished with it. To do that, call +kobject_put(). By doing this, the kobject core will automatically clean up +all of the memory allocated by this kobject. If a KOBJ_ADD uevent has been +sent for the object, a corresponding KOBJ_REMOVE uevent will be sent, and +any other sysfs housekeeping will be handled for the caller properly. -- sysfs_ops: Provides conversion functions for sysfs access. Please - see the sysfs documentation for more information. +If you need to do a two-stage delete of the kobject (say you are not +allowed to sleep when you need to destroy the object), then call +kobject_del() which will unregister the kobject from sysfs. This makes the +kobject "invisible", but it is not cleaned up, and the reference count of +the object is still the same. At a later time call kobject_put() to finish +the cleanup of the memory associated with the kobject. -- default_attrs: Default attributes to be exported via sysfs when the - object is registered.Note that the last attribute has to be - initialized to NULL ! You can find a complete implementation - in block/genhd.c +kobject_del() can be used to drop the reference to the parent object, if +circular references are constructed. It is valid in some cases, that a +parent objects references a child. Circular references _must_ be broken +with an explicit call to kobject_del(), so that a release functions will be +called, and the objects in the former circle release each other. -Instances of struct kobj_type are not registered; only referenced by -the kset. A kobj_type may be referenced by an arbitrary number of -ksets, as there may be disparate sets of identical objects. +Example code to copy from +For a more complete example of using ksets and kobjects properly, see the +sample/kobject/kset-example.c code. diff --git a/Documentation/pnp.txt b/Documentation/pnp.txt index 481faf515d5360e608b6f4541ef03f759612bc4f..a327db67782abacc792b60c2db02366078d47e7a 100644 --- a/Documentation/pnp.txt +++ b/Documentation/pnp.txt @@ -17,9 +17,9 @@ The User Interface ------------------ The Linux Plug and Play user interface provides a means to activate PnP devices for legacy and user level drivers that do not support Linux Plug and Play. The -user interface is integrated into driverfs. +user interface is integrated into sysfs. -In addition to the standard driverfs file the following are created in each +In addition to the standard sysfs file the following are created in each device's directory: id - displays a list of support EISA IDs options - displays possible resource configurations diff --git a/Documentation/s390/cds.txt b/Documentation/s390/cds.txt index 3081927cc2d64048c1bc02ddf0e33f737082f993..c4b7b2bd369ae74949cfd1182346dbc1d12427d6 100644 --- a/Documentation/s390/cds.txt +++ b/Documentation/s390/cds.txt @@ -133,7 +133,7 @@ During its startup the Linux/390 system checks for peripheral devices. Each of those devices is uniquely defined by a so called subchannel by the ESA/390 channel subsystem. While the subchannel numbers are system generated, each subchannel also takes a user defined attribute, the so called device number. -Both subchannel number and device number cannot exceed 65535. During driverfs +Both subchannel number and device number cannot exceed 65535. During sysfs initialisation, the information about control unit type and device types that imply specific I/O commands (channel command words - CCWs) in order to operate the device are gathered. Device drivers can retrieve this set of hardware diff --git a/Documentation/vm/slabinfo.c b/Documentation/vm/slabinfo.c index 7047696c47a18b6172549c9174b5988a7c2881c4..488c1f31b99249b75a9686cf42f08329bea896c9 100644 --- a/Documentation/vm/slabinfo.c +++ b/Documentation/vm/slabinfo.c @@ -1021,7 +1021,7 @@ void read_slab_dir(void) char *t; int count; - if (chdir("/sys/slab")) + if (chdir("/sys/kernel/slab")) fatal("SYSFS support for SLUB not active\n"); dir = opendir("."); diff --git a/Documentation/vm/slub.txt b/Documentation/vm/slub.txt index d17f324db9f51a538daccf3619b2eed445890525..dcf8bcf846d6a5486b737c840b4dce7d71ae89e2 100644 --- a/Documentation/vm/slub.txt +++ b/Documentation/vm/slub.txt @@ -63,7 +63,7 @@ In case you forgot to enable debugging on the kernel command line: It is possible to enable debugging manually when the kernel is up. Look at the contents of: -/sys/slab/<slab name>/ +/sys/kernel/slab/<slab name>/ Look at the writable files. Writing 1 to them will enable the corresponding debug option. All options can be set on a slab that does diff --git a/Documentation/zh_CN/CodingStyle b/Documentation/zh_CN/CodingStyle new file mode 100644 index 0000000000000000000000000000000000000000..ecd9307a641f0be6cfcc0ce61577e8b8765a5e44 --- /dev/null +++ b/Documentation/zh_CN/CodingStyle @@ -0,0 +1,701 @@ +Chinese translated version of Documentation/CodingStyle + +If you have any comment or update to the content, please post to LKML directly. +However, if you have problem communicating in English you can also ask the +Chinese maintainer for help. Contact the Chinese maintainer, if this +translation is outdated or there is problem with translation. + +Chinese maintainer: Zhang Le <r0bertz@gentoo.org> +--------------------------------------------------------------------- +Documentation/CodingStyleçš„ä¸æ–‡ç¿»è¯‘ + +如果想评论或更新本文的内容,请直接å‘信到LKMLã€‚å¦‚æžœä½ ä½¿ç”¨è‹±æ–‡äº¤æµæœ‰å›°éš¾çš„è¯ï¼Œä¹Ÿå¯ +以å‘ä¸æ–‡ç‰ˆç»´æŠ¤è€…求助。如果本翻译更新ä¸åŠæ—¶æˆ–者翻译å˜åœ¨é—®é¢˜ï¼Œè¯·è”ç³»ä¸æ–‡ç‰ˆç»´æŠ¤è€…。 + +ä¸æ–‡ç‰ˆç»´æŠ¤è€…: å¼ ä¹ Zhang Le <r0bertz@gentoo.org> +ä¸æ–‡ç‰ˆç¿»è¯‘者: å¼ ä¹ Zhang Le <r0bertz@gentoo.org> +ä¸æ–‡ç‰ˆæ ¡è¯‘者: çŽ‹èª Wang Cong <xiyou.wangcong@gmail.com> + wheelz <kernel.zeng@gmail.com> + 管æ—东 Xudong Guan <xudong.guan@gmail.com> + Li Zefan <lizf@cn.fujitsu.com> + Wang Chen <wangchen@cn.fujitsu.com> +以下为æ£æ–‡ +--------------------------------------------------------------------- + + Linuxå†…æ ¸ä»£ç é£Žæ ¼ + +这是一个简çŸçš„文档,æ述了linuxå†…æ ¸çš„é¦–é€‰ä»£ç é£Žæ ¼ã€‚ä»£ç é£Žæ ¼æ˜¯å› äººè€Œå¼‚çš„ï¼Œè€Œä¸”æˆ‘ +ä¸æ„¿æ„æŠŠæˆ‘çš„è§‚ç‚¹å¼ºåŠ ç»™ä»»ä½•äººï¼Œä¸è¿‡è¿™é‡Œæ‰€è®²è¿°çš„是我必须è¦ç»´æŠ¤çš„代ç 所éµå®ˆçš„é£Žæ ¼ï¼Œ +并且我也希望ç»å¤§å¤šæ•°å…¶ä»–代ç 也能éµå®ˆè¿™ä¸ªé£Žæ ¼ã€‚请在写代ç 时至少考虑一下本文所述的 +é£Žæ ¼ã€‚ + +é¦–å…ˆï¼Œæˆ‘å»ºè®®ä½ æ‰“å°ä¸€ä»½GNU代ç 规范,然åŽä¸è¦è¯»å®ƒã€‚烧了它,这是一个具有é‡å¤§è±¡å¾æ€§ +æ„义的动作。 + +ä¸ç®¡æ€Žæ ·ï¼ŒçŽ°åœ¨æˆ‘们开始: + + + ç¬¬ä¸€ç« ï¼šç¼©è¿› + +制表符是8个å—符,所以缩进也是8个å—符。有些异端è¿åŠ¨è¯•å›¾å°†ç¼©è¿›å˜ä¸º4(乃至2)个å—符 +æ·±ï¼Œè¿™å‡ ä¹Žç›¸å½“äºŽå°è¯•å°†åœ†å‘¨çŽ‡çš„值定义为3。 + +ç†ç”±ï¼šç¼©è¿›çš„全部æ„义就在于清楚的定义一个控制å—èµ·æ¢äºŽä½•å¤„ã€‚å°¤å…¶æ˜¯å½“ä½ ç›¯ç€ä½ çš„å±å¹• +è¿žç»çœ‹äº†20å°æ—¶ä¹‹åŽï¼Œä½ 将会å‘çŽ°å¤§ä¸€ç‚¹çš„ç¼©è¿›ä¼šä½¿ä½ æ›´å®¹æ˜“åˆ†è¾¨ç¼©è¿›ã€‚ + +现在,有些人会抱怨8个å—符的缩进会使代ç å‘å³è¾¹ç§»åŠ¨çš„太远,在80个å—符的终端å±å¹•ä¸Š +å°±å¾ˆéš¾è¯»è¿™æ ·çš„ä»£ç 。这个问题的ç”æ¡ˆæ˜¯ï¼Œå¦‚æžœä½ éœ€è¦3级以上的缩进,ä¸ç®¡ç”¨ä½•ç§æ–¹å¼ä½ +的代ç å·²ç»æœ‰é—®é¢˜äº†ï¼Œåº”该修æ£ä½ 的程åºã€‚ + +简而言之,8个å—符的缩进å¯ä»¥è®©ä»£ç æ›´å®¹æ˜“é˜…è¯»ï¼Œè¿˜æœ‰ä¸€ä¸ªå¥½å¤„æ˜¯å½“ä½ çš„å‡½æ•°åµŒå¥—å¤ªæ·±çš„ +时候å¯ä»¥ç»™ä½ è¦å‘Šã€‚留心这个è¦å‘Šã€‚ + +在switchè¯å¥ä¸æ¶ˆé™¤å¤šçº§ç¼©è¿›çš„首选的方å¼æ˜¯è®©â€œswitchâ€å’Œä»Žå±žäºŽå®ƒçš„“caseâ€æ ‡ç¾å¯¹é½äºŽåŒ +一列,而ä¸è¦â€œä¸¤æ¬¡ç¼©è¿›â€â€œcaseâ€æ ‡ç¾ã€‚比如: + + switch (suffix) { + case 'G': + case 'g': + mem <<= 30; + break; + case 'M': + case 'm': + mem <<= 20; + break; + case 'K': + case 'k': + mem <<= 10; + /* fall through */ + default: + break; + } + + +ä¸è¦æŠŠå¤šä¸ªè¯å¥æ”¾åœ¨ä¸€è¡Œé‡Œï¼Œé™¤éžä½ 有什么东西è¦éšè—: + + if (condition) do_this; + do_something_everytime; + +也ä¸è¦åœ¨ä¸€è¡Œé‡Œæ”¾å¤šä¸ªèµ‹å€¼è¯å¥ã€‚å†…æ ¸ä»£ç é£Žæ ¼è¶…çº§ç®€å•ã€‚就是é¿å…å¯èƒ½å¯¼è‡´åˆ«äººè¯¯è¯»çš„表 +è¾¾å¼ã€‚ + +除了注释ã€æ–‡æ¡£å’ŒKconfig之外,ä¸è¦ä½¿ç”¨ç©ºæ ¼æ¥ç¼©è¿›ï¼Œå‰é¢çš„例å是例外,是有æ„为之。 + +选用一个好的编辑器,ä¸è¦åœ¨è¡Œå°¾ç•™ç©ºæ ¼ã€‚ + + + ç¬¬äºŒç« ï¼šæŠŠé•¿çš„è¡Œå’Œå—符串打散 + +代ç é£Žæ ¼çš„æ„义就在于使用平常使用的工具æ¥ç»´æŒä»£ç çš„å¯è¯»æ€§å’Œå¯ç»´æŠ¤æ€§ã€‚ + +æ¯ä¸€è¡Œçš„长度的é™åˆ¶æ˜¯80列,我们强烈建议您éµå®ˆè¿™ä¸ªæƒ¯ä¾‹ã€‚ + +长于80列的è¯å¥è¦æ‰“æ•£æˆæœ‰æ„义的片段。æ¯ä¸ªç‰‡æ®µè¦æ˜Žæ˜¾çŸäºŽåŽŸæ¥çš„è¯å¥ï¼Œè€Œä¸”放置的ä½ç½® +也明显的é å³ã€‚åŒæ ·çš„规则也适用于有很长å‚数列表的函数头。长å—符串也è¦æ‰“æ•£æˆè¾ƒçŸçš„ +å—符串。唯一的例外是超过80列å¯ä»¥å¤§å¹…度æ高å¯è¯»æ€§å¹¶ä¸”ä¸ä¼šéšè—ä¿¡æ¯çš„情况。 + +void fun(int a, int b, int c) +{ + if (condition) + printk(KERN_WARNING "Warning this is a long printk with " + "3 parameters a: %u b: %u " + "c: %u \n", a, b, c); + else + next_statement; +} + + ç¬¬ä¸‰ç« ï¼šå¤§æ‹¬å·å’Œç©ºæ ¼çš„放置 + +Cè¯è¨€é£Žæ ¼ä¸å¦å¤–一个常è§é—®é¢˜æ˜¯å¤§æ‹¬å·çš„放置。和缩进大å°ä¸åŒï¼Œé€‰æ‹©æˆ–弃用æŸç§æ”¾ç½®ç– +ç•¥å¹¶æ²¡æœ‰å¤šå°‘æŠ€æœ¯ä¸Šçš„åŽŸå› ï¼Œä¸è¿‡é¦–选的方å¼ï¼Œå°±åƒKernighanå’ŒRitchie展示给我们的,是 +把起始大括å·æ”¾åœ¨è¡Œå°¾ï¼Œè€ŒæŠŠç»“æŸå¤§æ‹¬å·æ”¾åœ¨è¡Œé¦–,所以: + + if (x is true) { + we do y + } + +这适用于所有的éžå‡½æ•°è¯å¥å—(ifã€switchã€forã€whileã€do)。比如: + + switch (action) { + case KOBJ_ADD: + return "add"; + case KOBJ_REMOVE: + return "remove"; + case KOBJ_CHANGE: + return "change"; + default: + return NULL; + } + +ä¸è¿‡ï¼Œæœ‰ä¸€ä¸ªä¾‹å¤–,那就是函数:函数的起始大括å·æ”¾ç½®äºŽä¸‹ä¸€è¡Œçš„开头,所以: + + int function(int x) + { + body of function + } + +全世界的异端å¯èƒ½ä¼šæŠ±æ€¨è¿™ä¸ªä¸ä¸€è‡´æ€§æ˜¯â€¦â€¦å‘ƒâ€¦â€¦ä¸ä¸€è‡´çš„,ä¸è¿‡æ‰€æœ‰æ€ç»´å¥å…¨çš„人都知é“( +a)K&R是_æ£ç¡®çš„_,并且(b)K&R是æ£ç¡®çš„。æ¤å¤–,ä¸ç®¡æ€Žæ ·å‡½æ•°éƒ½æ˜¯ç‰¹æ®Šçš„(在Cè¯è¨€ä¸ +,函数是ä¸èƒ½åµŒå¥—的)。 + +注æ„结æŸå¤§æ‹¬å·ç‹¬è‡ªå æ®ä¸€è¡Œï¼Œé™¤éžå®ƒåŽé¢è·Ÿç€åŒä¸€ä¸ªè¯å¥çš„剩余部分,也就是doè¯å¥ä¸çš„ +“whileâ€æˆ–者ifè¯å¥ä¸çš„“elseâ€ï¼Œåƒè¿™æ ·ï¼š + + do { + body of do-loop + } while (condition); + +å’Œ + + if (x == y) { + .. + } else if (x > y) { + ... + } else { + .... + } + +ç†ç”±ï¼šK&R。 + +也请注æ„è¿™ç§å¤§æ‹¬å·çš„放置方å¼ä¹Ÿèƒ½ä½¿ç©ºï¼ˆæˆ–者差ä¸å¤šç©ºçš„)行的数é‡æœ€å°åŒ–,åŒæ—¶ä¸å¤±å¯ +è¯»æ€§ã€‚å› æ¤ï¼Œç”±äºŽä½ çš„å±å¹•ä¸Šçš„新行是ä¸å¯å†ç”Ÿèµ„æºï¼ˆæƒ³æƒ³25行的终端å±å¹•ï¼‰ï¼Œä½ 将会有更 +多的空行æ¥æ”¾ç½®æ³¨é‡Šã€‚ + +当åªæœ‰ä¸€ä¸ªå•ç‹¬çš„è¯å¥çš„时候,ä¸ç”¨åŠ ä¸å¿…è¦çš„大括å·ã€‚ + +if (condition) + action(); + +这点ä¸é€‚用于本身为æŸä¸ªæ¡ä»¶è¯å¥çš„一个分支的å•ç‹¬è¯å¥ã€‚这时需è¦åœ¨ä¸¤ä¸ªåˆ†æ”¯é‡Œéƒ½ä½¿ç”¨å¤§ +括å·ã€‚ + +if (condition) { + do_this(); + do_that(); +} else { + otherwise(); +} + + 3.1ï¼šç©ºæ ¼ + +Linuxå†…æ ¸çš„ç©ºæ ¼ä½¿ç”¨æ–¹å¼ï¼ˆä¸»è¦ï¼‰å–决于它是用于函数还是关键å—。(大多数)关键å—åŽ +è¦åŠ ä¸€ä¸ªç©ºæ ¼ã€‚å€¼å¾—æ³¨æ„的例外是sizeofã€typeofã€alignofå’Œ__attribute__ï¼Œè¿™äº›å…³é”®å— +æŸäº›ç¨‹åº¦ä¸Šçœ‹èµ·æ¥æ›´åƒå‡½æ•°ï¼ˆå®ƒä»¬åœ¨Linux里也常常伴éšå°æ‹¬å·è€Œä½¿ç”¨ï¼Œå°½ç®¡åœ¨Cè¯è¨€é‡Œè¿™æ · +çš„å°æ‹¬å·ä¸æ˜¯å¿…需的,就åƒâ€œstruct fileinfo infoâ€å£°æ˜Žè¿‡åŽçš„“sizeof infoâ€ï¼‰ã€‚ + +所以在这些关键å—之åŽæ”¾ä¸€ä¸ªç©ºæ ¼ï¼š + if, switch, case, for, do, while +但是ä¸è¦åœ¨sizeofã€typeofã€alignof或者__attribute__这些关键å—之åŽæ”¾ç©ºæ ¼ã€‚例如, + s = sizeof(struct file); + +ä¸è¦åœ¨å°æ‹¬å·é‡Œçš„表达å¼ä¸¤ä¾§åŠ ç©ºæ ¼ã€‚è¿™æ˜¯ä¸€ä¸ªå例: + + s = sizeof( struct file ); + +当声明指针类型或者返回指针类型的函数时,“*â€çš„首选使用方å¼æ˜¯ä½¿ä¹‹é è¿‘å˜é‡å或者函 +æ•°å,而ä¸æ˜¯é 近类型å。例å: + + char *linux_banner; + unsigned long long memparse(char *ptr, char **retptr); + char *match_strdup(substring_t *s); + +在大多数二元和三元æ“ä½œç¬¦ä¸¤ä¾§ä½¿ç”¨ä¸€ä¸ªç©ºæ ¼ï¼Œä¾‹å¦‚ä¸‹é¢æ‰€æœ‰è¿™äº›æ“作符: + + = + - < > * / % | & ^ <= >= == != ? : + +但是一元æ“作符åŽä¸è¦åŠ ç©ºæ ¼ï¼š + & * + - ~ ! sizeof typeof alignof __attribute__ defined + +åŽç¼€è‡ªåŠ 和自å‡ä¸€å…ƒæ“作符å‰ä¸åŠ ç©ºæ ¼ï¼š + ++ -- + +å‰ç¼€è‡ªåŠ 和自å‡ä¸€å…ƒæ“作符åŽä¸åŠ ç©ºæ ¼ï¼š + ++ -- + +“.â€å’Œâ€œ->â€ç»“构体æˆå‘˜æ“作符å‰åŽä¸åŠ ç©ºæ ¼ã€‚ + +ä¸è¦åœ¨è¡Œå°¾ç•™ç©ºç™½ã€‚有些å¯ä»¥è‡ªåŠ¨ç¼©è¿›çš„ç¼–è¾‘å™¨ä¼šåœ¨æ–°è¡Œçš„è¡Œé¦–åŠ å…¥é€‚é‡çš„空白,然åŽä½ +å°±å¯ä»¥ç›´æŽ¥åœ¨é‚£ä¸€è¡Œè¾“入代ç 。ä¸è¿‡å‡å¦‚ä½ æœ€åŽæ²¡æœ‰åœ¨é‚£ä¸€è¡Œè¾“入代ç ï¼Œæœ‰äº›ç¼–è¾‘å™¨å°±ä¸ +会移除已ç»åŠ 入的空白,就åƒä½ æ•…æ„留下一个åªæœ‰ç©ºç™½çš„行。包å«è¡Œå°¾ç©ºç™½çš„è¡Œå°±è¿™æ ·äº§ +生了。 + +当gitå‘现补ä¸åŒ…å«äº†è¡Œå°¾ç©ºç™½çš„时候会è¦å‘Šä½ ,并且å¯ä»¥åº”ä½ çš„è¦æ±‚去掉行尾空白;ä¸è¿‡ +å¦‚æžœä½ æ˜¯æ£åœ¨æ‰“一系列补ä¸ï¼Œè¿™æ ·åšä¼šå¯¼è‡´åŽé¢çš„è¡¥ä¸å¤±è´¥ï¼Œå› ä¸ºä½ æ”¹å˜äº†è¡¥ä¸çš„上下文。 + + + ç¬¬å››ç« ï¼šå‘½å + +C是一个简朴的è¯è¨€ï¼Œä½ 的命åä¹Ÿåº”è¯¥è¿™æ ·ã€‚å’ŒModula-2å’ŒPascal程åºå‘˜ä¸åŒï¼ŒC程åºå‘˜ä¸ä½¿ +用类似ThisVariableIsATemporaryCounterè¿™æ ·åŽä¸½çš„åå—。C程åºå‘˜ä¼šç§°é‚£ä¸ªå˜é‡ä¸ºâ€œtmp†+ï¼Œè¿™æ ·å†™èµ·æ¥ä¼šæ›´å®¹æ˜“,而且至少ä¸ä¼šä»¤å…¶éš¾äºŽç†è§£ã€‚ + +ä¸è¿‡ï¼Œè™½ç„¶æ··ç”¨å¤§å°å†™çš„åå—是ä¸æ倡使用的,但是全局å˜é‡è¿˜æ˜¯éœ€è¦ä¸€ä¸ªå…·æ述性的åå— +。称一个全局函数为“fooâ€æ˜¯ä¸€ä¸ªéš¾ä»¥é¥¶æ•çš„错误。 + +全局å˜é‡ï¼ˆåªæœ‰å½“ä½ çœŸæ£éœ€è¦å®ƒä»¬çš„时候å†ç”¨å®ƒï¼‰éœ€è¦æœ‰ä¸€ä¸ªå…·æ述性的åå—,就åƒå…¨å±€å‡½ +æ•°ã€‚å¦‚æžœä½ æœ‰ä¸€ä¸ªå¯ä»¥è®¡ç®—活动用户数é‡çš„å‡½æ•°ï¼Œä½ åº”è¯¥å«å®ƒâ€œcount_active_users()â€æˆ–者 +类似的åå—ï¼Œä½ ä¸åº”该å«å®ƒâ€œcntuser()â€ã€‚ + +在函数åä¸åŒ…å«å‡½æ•°ç±»åž‹ï¼ˆæ‰€è°“的匈牙利命å法)是脑å出了问题——编译器知é“那些类型而 +ä¸”èƒ½å¤Ÿæ£€æŸ¥é‚£äº›ç±»åž‹ï¼Œè¿™æ ·åšåªèƒ½æŠŠç¨‹åºå‘˜å¼„ç³Šæ¶‚äº†ã€‚éš¾æ€ªå¾®è½¯æ€»æ˜¯åˆ¶é€ å‡ºæœ‰é—®é¢˜çš„ç¨‹åºã€‚ + +本地å˜é‡å应该简çŸï¼Œè€Œä¸”能够表达相关的å«ä¹‰ã€‚å¦‚æžœä½ æœ‰ä¸€äº›éšæœºçš„整数型的循环计数器 +,它应该被称为“iâ€ã€‚å«å®ƒâ€œloop_counterâ€å¹¶æ— 益处,如果它没有被误解的å¯èƒ½çš„è¯ã€‚类似 +的,“tmpâ€å¯ä»¥ç”¨æ¥ç§°å‘¼ä»»æ„类型的临时å˜é‡ã€‚ + +å¦‚æžœä½ æ€•æ··æ·†äº†ä½ çš„æœ¬åœ°å˜é‡åï¼Œä½ å°±é‡åˆ°å¦ä¸€ä¸ªé—®é¢˜äº†ï¼Œå«åšå‡½æ•°å¢žé•¿è·å°”蒙失衡综åˆç—‡ +。请看第å…ç« ï¼ˆå‡½æ•°ï¼‰ã€‚ + + + ç¬¬äº”ç« ï¼šTypedef + +ä¸è¦ä½¿ç”¨ç±»ä¼¼â€œvps_tâ€ä¹‹ç±»çš„东西。 + +对结构体和指针使用typedefæ˜¯ä¸€ä¸ªé”™è¯¯ã€‚å½“ä½ åœ¨ä»£ç 里看到: + + vps_t a; + +这代表什么æ„æ€å‘¢ï¼Ÿ + +相åï¼Œå¦‚æžœæ˜¯è¿™æ · + + struct virtual_container *a; + +ä½ å°±çŸ¥é““aâ€æ˜¯ä»€ä¹ˆäº†ã€‚ + +很多人认为typedef“能æ高å¯è¯»æ€§â€ã€‚实际ä¸æ˜¯è¿™æ ·çš„。它们åªåœ¨ä¸‹åˆ—情况下有用: + + (a) 完全ä¸é€æ˜Žçš„对象(这ç§æƒ…况下è¦ä¸»åŠ¨ä½¿ç”¨typedefæ¥éšè—这个对象实际上是什么)。 + + 例如:“pte_tâ€ç‰ä¸é€æ˜Žå¯¹è±¡ï¼Œä½ åªèƒ½ç”¨åˆé€‚的访问函数æ¥è®¿é—®å®ƒä»¬ã€‚ + + 注æ„ï¼ä¸é€æ˜Žæ€§å’Œâ€œè®¿é—®å‡½æ•°â€æœ¬èº«æ˜¯ä¸å¥½çš„。我们使用pte_tç‰ç±»åž‹çš„åŽŸå› åœ¨äºŽçœŸçš„æ˜¯ + 完全没有任何共用的å¯è®¿é—®ä¿¡æ¯ã€‚ + + (b) 清楚的整数类型,如æ¤ï¼Œè¿™å±‚抽象就å¯ä»¥å¸®åŠ©æ¶ˆé™¤åˆ°åº•æ˜¯â€œintâ€è¿˜æ˜¯â€œlongâ€çš„混淆。 + + u8/u16/u32是完全没有问题的typedef,ä¸è¿‡å®ƒä»¬æ›´ç¬¦åˆç±»åˆ«(d)而ä¸æ˜¯è¿™é‡Œã€‚ + + å†æ¬¡æ³¨æ„ï¼è¦è¿™æ ·åšï¼Œå¿…é¡»äº‹å‡ºæœ‰å› ã€‚å¦‚æžœæŸä¸ªå˜é‡æ˜¯â€œunsigned longâ€œï¼Œé‚£ä¹ˆæ²¡æœ‰å¿…è¦ + + typedef unsigned long myflags_t; + + ä¸è¿‡å¦‚æžœæœ‰ä¸€ä¸ªæ˜Žç¡®çš„åŽŸå› ï¼Œæ¯”å¦‚å®ƒåœ¨æŸç§æƒ…况下å¯èƒ½ä¼šæ˜¯ä¸€ä¸ªâ€œunsigned intâ€è€Œåœ¨ + 其他情况下å¯èƒ½ä¸ºâ€œunsigned longâ€ï¼Œé‚£ä¹ˆå°±ä¸è¦çŠ¹è±«ï¼Œè¯·åŠ¡å¿…使用typedef。 + + (c) å½“ä½ ä½¿ç”¨sparse按å—é¢çš„创建一个新类型æ¥åšç±»åž‹æ£€æŸ¥çš„时候。 + + (d) å’Œæ ‡å‡†C99类型相åŒçš„类型,在æŸäº›ä¾‹å¤–的情况下。 + + 虽然让眼ç›å’Œè„‘ç‹æ¥é€‚åº”æ–°çš„æ ‡å‡†ç±»åž‹æ¯”å¦‚â€œuint32_tâ€ä¸éœ€è¦èŠ±å¾ˆå¤šæ—¶é—´ï¼Œå¯æ˜¯æœ‰äº› + 人ä»ç„¶æ‹’ç»ä½¿ç”¨å®ƒä»¬ã€‚ + + å› æ¤ï¼ŒLinux特有的ç‰åŒäºŽæ ‡å‡†ç±»åž‹çš„“u8/u16/u32/u64â€ç±»åž‹å’Œå®ƒä»¬çš„有符å·ç±»åž‹æ˜¯è¢« + å…è®¸çš„â€”â€”å°½ç®¡åœ¨ä½ è‡ªå·±çš„æ–°ä»£ç ä¸ï¼Œå®ƒä»¬ä¸æ˜¯å¼ºåˆ¶è¦æ±‚è¦ä½¿ç”¨çš„。 + + 当编辑已ç»ä½¿ç”¨äº†æŸä¸ªç±»åž‹é›†çš„已有代ç æ—¶ï¼Œä½ åº”è¯¥éµå¾ªé‚£äº›ä»£ç ä¸å·²ç»åšå‡ºçš„选择。 + + (e) å¯ä»¥åœ¨ç”¨æˆ·ç©ºé—´å®‰å…¨ä½¿ç”¨çš„类型。 + + 在æŸäº›ç”¨æˆ·ç©ºé—´å¯è§çš„结构体里,我们ä¸èƒ½è¦æ±‚C99类型而且ä¸èƒ½ç”¨ä¸Šé¢æ到的“u32†+ ç±»åž‹ã€‚å› æ¤ï¼Œæˆ‘们在与用户空间共享的所有结构体ä¸ä½¿ç”¨__u32和类似的类型。 + +å¯èƒ½è¿˜æœ‰å…¶ä»–的情况,ä¸è¿‡åŸºæœ¬çš„规则是永远ä¸è¦ä½¿ç”¨typedef,除éžä½ å¯ä»¥æ˜Žç¡®çš„应用上 +è¿°æŸä¸ªè§„则ä¸çš„一个。 + +总的æ¥è¯´ï¼Œå¦‚æžœä¸€ä¸ªæŒ‡é’ˆæˆ–è€…ä¸€ä¸ªç»“æž„ä½“é‡Œçš„å…ƒç´ å¯ä»¥åˆç†çš„è¢«ç›´æŽ¥è®¿é—®åˆ°ï¼Œé‚£ä¹ˆå®ƒä»¬å°±ä¸ +应该是一个typedef。 + + + 第å…ç« ï¼šå‡½æ•° + +函数应该简çŸè€Œæ¼‚亮,并且åªå®Œæˆä¸€ä»¶äº‹æƒ…。函数应该å¯ä»¥ä¸€å±æˆ–者两å±æ˜¾ç¤ºå®Œï¼ˆæˆ‘们都知 +é“ISO/ANSIå±å¹•å¤§å°æ˜¯80x24),åªåšä¸€ä»¶äº‹æƒ…,而且把它åšå¥½ã€‚ + +一个函数的最大长度是和该函数的å¤æ‚度和缩进级数æˆåæ¯”çš„ã€‚æ‰€ä»¥ï¼Œå¦‚æžœä½ æœ‰ä¸€ä¸ªç†è®ºä¸Š +很简å•çš„åªæœ‰ä¸€ä¸ªå¾ˆé•¿ï¼ˆä½†æ˜¯ç®€å•ï¼‰çš„caseè¯å¥çš„å‡½æ•°ï¼Œè€Œä¸”ä½ éœ€è¦åœ¨æ¯ä¸ªcase里åšå¾ˆå¤šå¾ˆ +å°çš„äº‹æƒ…ï¼Œè¿™æ ·çš„å‡½æ•°å°½ç®¡å¾ˆé•¿ï¼Œä½†ä¹Ÿæ˜¯å¯ä»¥çš„。 + +ä¸è¿‡ï¼Œå¦‚æžœä½ æœ‰ä¸€ä¸ªå¤æ‚çš„å‡½æ•°ï¼Œè€Œä¸”ä½ æ€€ç–‘ä¸€ä¸ªå¤©åˆ†ä¸æ˜¯å¾ˆé«˜çš„高ä¸ä¸€å¹´çº§å¦ç”Ÿå¯èƒ½ç”šè‡³ +æžä¸æ¸…æ¥šè¿™ä¸ªå‡½æ•°çš„ç›®çš„ï¼Œä½ åº”è¯¥ä¸¥æ ¼çš„éµå®ˆå‰é¢æ到的长度é™åˆ¶ã€‚使用辅助函数,并为之 +å–个具æ述性的åå—ï¼ˆå¦‚æžœä½ è§‰å¾—å®ƒä»¬çš„æ€§èƒ½å¾ˆé‡è¦çš„è¯ï¼Œå¯ä»¥è®©ç¼–译器内è”å®ƒä»¬ï¼Œè¿™æ ·çš„ +æ•ˆæžœå¾€å¾€ä¼šæ¯”ä½ å†™ä¸€ä¸ªå¤æ‚函数的效果è¦å¥½ã€‚) + +函数的å¦å¤–一个衡é‡æ ‡å‡†æ˜¯æœ¬åœ°å˜é‡çš„æ•°é‡ã€‚æ¤æ•°é‡ä¸åº”超过5ï¼10个,å¦åˆ™ä½ 的函数就有 +问题了。é‡æ–°è€ƒè™‘ä¸€ä¸‹ä½ çš„å‡½æ•°ï¼ŒæŠŠå®ƒåˆ†æ‹†æˆæ›´å°çš„函数。人的大脑一般å¯ä»¥è½»æ¾çš„åŒæ—¶è·Ÿ +踪7个ä¸åŒçš„事物,如果å†å¢žå¤šçš„è¯ï¼Œå°±ä¼šç³Šæ¶‚了。å³ä¾¿ä½ èªé¢–è¿‡äººï¼Œä½ ä¹Ÿå¯èƒ½ä¼šè®°ä¸æ¸…ä½ 2 +个星期å‰åšè¿‡çš„事情。 + +在æºæ–‡ä»¶é‡Œï¼Œä½¿ç”¨ç©ºè¡Œéš”å¼€ä¸åŒçš„函数。如果该函数需è¦è¢«å¯¼å‡ºï¼Œå®ƒçš„EXPORT*å®åº”该紧贴 +在它的结æŸå¤§æ‹¬å·ä¹‹ä¸‹ã€‚比如: + +int system_is_up(void) +{ + return system_state == SYSTEM_RUNNING; +} +EXPORT_SYMBOL(system_is_up); + +在函数原型ä¸ï¼ŒåŒ…å«å‡½æ•°å和它们的数æ®ç±»åž‹ã€‚虽然Cè¯è¨€é‡Œæ²¡æœ‰è¿™æ ·çš„è¦æ±‚,在Linux里这 +是æ倡的åšæ³•ï¼Œå› ä¸ºè¿™æ ·å¯ä»¥å¾ˆç®€å•çš„给读者æ供更多的有价值的信æ¯ã€‚ + + + ç¬¬ä¸ƒç« ï¼šé›†ä¸çš„函数退出途径 + +虽然被æŸäº›äººå£°ç§°å·²ç»è¿‡æ—¶ï¼Œä½†æ˜¯gotoè¯å¥çš„ç‰ä»·ç‰©è¿˜æ˜¯ç»å¸¸è¢«ç¼–译器所使用,具体形å¼æ˜¯ +æ— æ¡ä»¶è·³è½¬æŒ‡ä»¤ã€‚ + +当一个函数从多个ä½ç½®é€€å‡ºå¹¶ä¸”需è¦åšä¸€äº›é€šç”¨çš„清ç†å·¥ä½œçš„时候,gotoçš„å¥½å¤„å°±æ˜¾çŽ°å‡ºæ¥ +了。 + +ç†ç”±æ˜¯ï¼š + +- æ— æ¡ä»¶è¯å¥å®¹æ˜“ç†è§£å’Œè·Ÿè¸ª +- 嵌套程度å‡å° +- å¯ä»¥é¿å…由于修改时忘记更新æŸä¸ªå•ç‹¬çš„退出点而导致的错误 +- å‡è½»äº†ç¼–è¯‘å™¨çš„å·¥ä½œï¼Œæ— éœ€åˆ é™¤å†—ä½™ä»£ç ;) + +int fun(int a) +{ + int result = 0; + char *buffer = kmalloc(SIZE); + + if (buffer == NULL) + return -ENOMEM; + + if (condition1) { + while (loop1) { + ... + } + result = 1; + goto out; + } + ... +out: + kfree(buffer); + return result; +} + + ç¬¬å…«ç« ï¼šæ³¨é‡Š + +注释是好的,ä¸è¿‡æœ‰è¿‡åº¦æ³¨é‡Šçš„å±é™©ã€‚永远ä¸è¦åœ¨æ³¨é‡Šé‡Œè§£é‡Šä½ 的代ç 是如何è¿ä½œçš„:更好 +çš„åšæ³•æ˜¯è®©åˆ«äººä¸€çœ‹ä½ 的代ç å°±å¯ä»¥æ˜Žç™½ï¼Œè§£é‡Šå†™çš„很差的代ç 是浪费时间。 + +ä¸€èˆ¬çš„ï¼Œä½ æƒ³è¦ä½ çš„æ³¨é‡Šå‘Šè¯‰åˆ«äººä½ çš„ä»£ç åšäº†ä»€ä¹ˆï¼Œè€Œä¸æ˜¯æ€Žä¹ˆåšçš„ã€‚ä¹Ÿè¯·ä½ ä¸è¦æŠŠæ³¨é‡Š +放在一个函数体内部:如果函数å¤æ‚åˆ°ä½ éœ€è¦ç‹¬ç«‹çš„注释其ä¸çš„ä¸€éƒ¨åˆ†ï¼Œä½ å¾ˆå¯èƒ½éœ€è¦å›žåˆ° +第å…ç« çœ‹ä¸€çœ‹ã€‚ä½ å¯ä»¥åšä¸€äº›å°æ³¨é‡Šæ¥æ³¨æ˜Žæˆ–è¦å‘ŠæŸäº›å¾ˆèªæ˜Žï¼ˆæˆ–者槽糕)的åšæ³•ï¼Œä½†ä¸è¦ +åŠ å¤ªå¤šã€‚ä½ åº”è¯¥åšçš„,是把注释放在函数的头部,告诉人们它åšäº†ä»€ä¹ˆï¼Œä¹Ÿå¯ä»¥åŠ 上它åšè¿™ +äº›äº‹æƒ…çš„åŽŸå› ã€‚ + +å½“æ³¨é‡Šå†…æ ¸API函数时,请使用kernel-docæ ¼å¼ã€‚请看 +Documentation/kernel-doc-nano-HOWTO.txtå’Œscripts/kernel-doc以获得详细信æ¯ã€‚ + +Linuxçš„æ³¨é‡Šé£Žæ ¼æ˜¯C89“/* ... */â€é£Žæ ¼ã€‚ä¸è¦ä½¿ç”¨C99é£Žæ ¼â€œ// ...â€æ³¨é‡Šã€‚ + +é•¿ï¼ˆå¤šè¡Œï¼‰çš„é¦–é€‰æ³¨é‡Šé£Žæ ¼æ˜¯ï¼š + + /* + * This is the preferred style for multi-line + * comments in the Linux kernel source code. + * Please use it consistently. + * + * Description: A column of asterisks on the left side, + * with beginning and ending almost-blank lines. + */ + +注释数æ®ä¹Ÿæ˜¯å¾ˆé‡è¦çš„,ä¸ç®¡æ˜¯åŸºæœ¬ç±»åž‹è¿˜æ˜¯è¡ç”Ÿç±»åž‹ã€‚为了方便实现这一点,æ¯ä¸€è¡Œåº”åª +声明一个数æ®ï¼ˆä¸è¦ä½¿ç”¨é€—å·æ¥ä¸€æ¬¡å£°æ˜Žå¤šä¸ªæ•°æ®ï¼‰ã€‚è¿™æ ·ä½ å°±æœ‰ç©ºé—´æ¥ä¸ºæ¯ä¸ªæ•°æ®å†™ä¸€æ®µ +å°æ³¨é‡Šæ¥è§£é‡Šå®ƒä»¬çš„用途了。 + + + 第ä¹ç« ï¼šä½ å·²ç»æŠŠäº‹æƒ…弄糟了 + +è¿™æ²¡ä»€ä¹ˆï¼Œæˆ‘ä»¬éƒ½æ˜¯è¿™æ ·ã€‚å¯èƒ½ä½ 的使用了很长时间Unix的朋å‹å·²ç»å‘Šè¯‰ä½ “GNU emacsâ€èƒ½ +è‡ªåŠ¨å¸®ä½ æ ¼å¼åŒ–Cæºä»£ç ï¼Œè€Œä¸”ä½ ä¹Ÿæ³¨æ„åˆ°äº†ï¼Œç¡®å®žæ˜¯è¿™æ ·ï¼Œä¸è¿‡å®ƒæ‰€ä½¿ç”¨çš„默认值和我们 +想è¦çš„相去甚远(实际上,甚至比éšæœºæ‰“的还è¦å·®â€”â€”æ— æ•°ä¸ªçŒ´å在GNU emacs里打å—æ°¸è¿œä¸ +ä¼šåˆ›é€ å‡ºä¸€ä¸ªå¥½ç¨‹åºï¼‰ï¼ˆè¯‘注:请å‚考Infinite Monkey Theorem) + +æ‰€ä»¥ä½ è¦ä¹ˆæ”¾å¼ƒGNU emacs,è¦ä¹ˆæ”¹å˜å®ƒè®©å®ƒä½¿ç”¨æ›´åˆç†çš„设定。è¦é‡‡ç”¨åŽä¸€ä¸ªæ–¹æ¡ˆï¼Œä½ å¯ +以把下é¢è¿™æ®µç²˜è´´åˆ°ä½ çš„.emacs文件里。 + +(defun linux-c-mode () + "C mode with adjusted defaults for use with the Linux kernel." + (interactive) + (c-mode) + (c-set-style "K&R") + (setq tab-width 8) + (setq indent-tabs-mode t) + (setq c-basic-offset 8)) + +è¿™æ ·å°±å®šä¹‰äº†M-x linux-c-modeå‘½ä»¤ã€‚å½“ä½ hack一个模å—çš„æ—¶å€™ï¼Œå¦‚æžœä½ æŠŠå—符串 +-*- linux-c -*-放在头两行的æŸä¸ªä½ç½®ï¼Œè¿™ä¸ªæ¨¡å¼å°†ä¼šè¢«è‡ªåŠ¨è°ƒç”¨ã€‚å¦‚æžœä½ å¸Œæœ›åœ¨ä½ ä¿®æ”¹ +/usr/src/linux里的文件时é”术般自动打开linux-c-modeçš„è¯ï¼Œä½ 也å¯èƒ½éœ€è¦æ·»åŠ + +(setq auto-mode-alist (cons '("/usr/src/linux.*/.*\\.[ch]$" . linux-c-mode) + auto-mode-alist)) + +åˆ°ä½ çš„.emacs文件里。 + +ä¸è¿‡å°±ç®—ä½ å°è¯•è®©emacsæ£ç¡®çš„æ ¼å¼åŒ–代ç 失败了,也并ä¸æ„味ç€ä½ 失去了一切:还å¯ä»¥ç”¨â€œ +indentâ€ã€‚ + +ä¸è¿‡ï¼ŒGNU indent也有和GNU emacsä¸€æ ·æœ‰é—®é¢˜çš„è®¾å®šï¼Œæ‰€ä»¥ä½ éœ€è¦ç»™å®ƒä¸€äº›å‘½ä»¤é€‰é¡¹ã€‚ä¸ +过,这还ä¸ç®—å¤ªç³Ÿç³•ï¼Œå› ä¸ºå°±ç®—æ˜¯GNU indent的作者也认åŒK&Rçš„æƒå¨æ€§ï¼ˆGNU的人并ä¸æ˜¯å +人,他们åªæ˜¯åœ¨è¿™ä¸ªé—®é¢˜ä¸Šè¢«ä¸¥é‡çš„è¯¯å¯¼äº†ï¼‰ï¼Œæ‰€ä»¥ä½ åªè¦ç»™indent指定选项“-kr -i8†+(代表“K&R,8个å—符缩进â€ï¼‰ï¼Œæˆ–者使用“scripts/Lindentâ€ï¼Œè¿™æ ·å°±å¯ä»¥ä»¥æœ€æ—¶é«¦çš„æ–¹å¼ +缩进æºä»£ç 。 + +“indentâ€æœ‰å¾ˆå¤šé€‰é¡¹ï¼Œç‰¹åˆ«æ˜¯é‡æ–°æ ¼å¼åŒ–æ³¨é‡Šçš„æ—¶å€™ï¼Œä½ å¯èƒ½éœ€è¦çœ‹ä¸€ä¸‹å®ƒçš„手册页。ä¸è¿‡ +è®°ä½ï¼šâ€œindentâ€ä¸èƒ½ä¿®æ£åçš„ç¼–ç¨‹ä¹ æƒ¯ã€‚ + + + 第åç« ï¼šKconfigé…置文件 + +对于é布æºç æ ‘çš„æ‰€æœ‰Kconfig*é…置文件æ¥è¯´ï¼Œå®ƒä»¬ç¼©è¿›æ–¹å¼ä¸ŽC代ç 相比有所ä¸åŒã€‚紧挨 +在“configâ€å®šä¹‰ä¸‹é¢çš„行缩进一个制表符,帮助信æ¯åˆ™å†å¤šç¼©è¿›2ä¸ªç©ºæ ¼ã€‚æ¯”å¦‚ï¼š + +config AUDIT + bool "Auditing support" + depends on NET + help + Enable auditing infrastructure that can be used with another + kernel subsystem, such as SELinux (which requires this for + logging of avc messages output). Does not do system-call + auditing without CONFIG_AUDITSYSCALL. + +ä»ç„¶è¢«è®¤ä¸ºä¸å¤Ÿç¨³å®šçš„功能应该被定义为ä¾èµ–于“EXPERIMENTALâ€ï¼š + +config SLUB + depends on EXPERIMENTAL && !ARCH_USES_SLAB_PAGE_STRUCT + bool "SLUB (Unqueued Allocator)" + ... + +而那些å±é™©çš„功能(比如æŸäº›æ–‡ä»¶ç³»ç»Ÿçš„写支æŒï¼‰åº”该在它们的æ示å—符串里显著的声明这 +一点: + +config ADFS_FS_RW + bool "ADFS write support (DANGEROUS)" + depends on ADFS_FS + ... + +è¦æŸ¥çœ‹é…置文件的完整文档,请看Documentation/kbuild/kconfig-language.txt。 + + + 第åä¸€ç« ï¼šæ•°æ®ç»“æž„ + +如果一个数æ®ç»“构,在创建和销æ¯å®ƒçš„å•çº¿æ‰§è¡ŒçŽ¯å¢ƒä¹‹å¤–å¯è§ï¼Œé‚£ä¹ˆå®ƒå¿…é¡»è¦æœ‰ä¸€ä¸ªå¼•ç”¨è®¡ +æ•°å™¨ã€‚å†…æ ¸é‡Œæ²¡æœ‰åžƒåœ¾æ”¶é›†ï¼ˆå¹¶ä¸”å†…æ ¸ä¹‹å¤–çš„åžƒåœ¾æ”¶é›†æ…¢ä¸”æ•ˆçŽ‡ä½Žä¸‹ï¼‰ï¼Œè¿™æ„味ç€ä½ ç»å¯¹éœ€ +è¦è®°å½•ä½ 对这ç§æ•°æ®ç»“构的使用情况。 + +引用计数æ„味ç€ä½ 能够é¿å…上é”,并且å…许多个用户并行访问这个数æ®ç»“构——而ä¸éœ€è¦æ‹…心 +这个数æ®ç»“æž„ä»…ä»…å› ä¸ºæš‚æ—¶ä¸è¢«ä½¿ç”¨å°±æ¶ˆå¤±äº†ï¼Œé‚£äº›ç”¨æˆ·å¯èƒ½ä¸è¿‡æ˜¯æ²‰ç¡äº†ä¸€é˜µæˆ–者åšäº†ä¸€ +些其他事情而已。 + +注æ„上é”ä¸èƒ½å–代引用计数。上é”是为了ä¿æŒæ•°æ®ç»“构的一致性,而引用计数是一个内å˜ç®¡ +ç†æŠ€å·§ã€‚通常二者都需è¦ï¼Œä¸è¦æŠŠä¸¤ä¸ªæžæ··äº†ã€‚ + +很多数æ®ç»“构实际上有2级引用计数,它们通常有ä¸åŒâ€œç±»â€çš„用户。å类计数器统计å类用 +户的数é‡ï¼Œæ¯å½“å类计数器å‡è‡³é›¶æ—¶ï¼Œå…¨å±€è®¡æ•°å™¨å‡ä¸€ã€‚ + +è¿™ç§â€œå¤šçº§å¼•ç”¨è®¡æ•°â€çš„例åå¯ä»¥åœ¨å†…å˜ç®¡ç†ï¼ˆâ€œstruct mm_structâ€ï¼šmm_userså’Œmm_count) +和文件系统(“struct super_blockâ€ï¼šs_countå’Œs_active)ä¸æ‰¾åˆ°ã€‚ + +è®°ä½ï¼šå¦‚æžœå¦ä¸€ä¸ªæ‰§è¡Œçº¿ç´¢å¯ä»¥æ‰¾åˆ°ä½ çš„æ•°æ®ç»“构,但是这个数æ®ç»“构没有引用计数器,这 +é‡Œå‡ ä¹Žè‚¯å®šæ˜¯ä¸€ä¸ªbug。 + + + 第åäºŒç« ï¼šå®ï¼Œæžšä¸¾å’ŒRTL + +用于定义常é‡çš„å®çš„åå—åŠæžšä¸¾é‡Œçš„æ ‡ç¾éœ€è¦å¤§å†™ã€‚ + +#define CONSTANT 0x12345 + +åœ¨å®šä¹‰å‡ ä¸ªç›¸å…³çš„å¸¸é‡æ—¶ï¼Œæœ€å¥½ç”¨æžšä¸¾ã€‚ + +å®çš„åå—请用大写å—æ¯ï¼Œä¸è¿‡å½¢å¦‚函数的å®çš„åå—å¯ä»¥ç”¨å°å†™å—æ¯ã€‚ + +一般的,如果能写æˆå†…è”函数就ä¸è¦å†™æˆåƒå‡½æ•°çš„å®ã€‚ + +å«æœ‰å¤šä¸ªè¯å¥çš„å®åº”该被包å«åœ¨ä¸€ä¸ªdo-while代ç å—里: + +#define macrofun(a, b, c) \ + do { \ + if (a == 5) \ + do_this(b, c); \ + } while (0) + +使用å®çš„时候应é¿å…的事情: + +1) å½±å“控制æµç¨‹çš„å®ï¼š + +#define FOO(x) \ + do { \ + if (blah(x) < 0) \ + return -EBUGGERED; \ + } while(0) + +éžå¸¸ä¸å¥½ã€‚它看起æ¥åƒä¸€ä¸ªå‡½æ•°ï¼Œä¸è¿‡å´èƒ½å¯¼è‡´â€œè°ƒç”¨â€å®ƒçš„函数退出;ä¸è¦æ‰“乱读者大脑里 +çš„è¯æ³•åˆ†æžå™¨ã€‚ + +2) ä¾èµ–于一个固定åå—的本地å˜é‡çš„å®ï¼š + +#define FOO(val) bar(index, val) + +å¯èƒ½çœ‹èµ·æ¥åƒæ˜¯ä¸ªä¸é”™çš„东西,ä¸è¿‡å®ƒéžå¸¸å®¹æ˜“把读代ç 的人æžç³Šæ¶‚ï¼Œè€Œä¸”å®¹æ˜“å¯¼è‡´çœ‹èµ·æ¥ +ä¸ç›¸å…³çš„改动带æ¥é”™è¯¯ã€‚ + +3) 作为左值的带å‚æ•°çš„å®ï¼š FOO(x) = y;如果有人把FOOå˜æˆä¸€ä¸ªå†…è”函数的è¯ï¼Œè¿™ç§ç”¨ +法就会出错了。 + +4) 忘记了优先级:使用表达å¼å®šä¹‰å¸¸é‡çš„å®å¿…须将表达å¼ç½®äºŽä¸€å¯¹å°æ‹¬å·ä¹‹å†…。带å‚æ•°çš„ +å®ä¹Ÿè¦æ³¨æ„æ¤ç±»é—®é¢˜ã€‚ + +#define CONSTANT 0x4000 +#define CONSTEXP (CONSTANT | 3) + +cpp手册对å®çš„讲解很详细。Gcc internals手册也详细讲解了RTL(译注:register +transfer languageï¼‰ï¼Œå†…æ ¸é‡Œçš„æ±‡ç¼–è¯è¨€ç»å¸¸ç”¨åˆ°å®ƒã€‚ + + + 第åä¸‰ç« ï¼šæ‰“å°å†…æ ¸æ¶ˆæ¯ + +å†…æ ¸å¼€å‘者应该是å—过良好教育的。请一定注æ„å†…æ ¸ä¿¡æ¯çš„拼写,以给人以好的å°è±¡ã€‚ä¸è¦ +用ä¸è§„范的å•è¯æ¯”如“dontâ€ï¼Œè€Œè¦ç”¨â€œdo notâ€æˆ–者“don'tâ€ã€‚ä¿è¯è¿™äº›ä¿¡æ¯ç®€å•ã€æ˜Žäº†ã€æ— +æ§ä¹‰ã€‚ + +å†…æ ¸ä¿¡æ¯ä¸å¿…以å¥å·ï¼ˆè¯‘注:英文å¥å·ï¼Œå³ç‚¹ï¼‰ç»“æŸã€‚ + +在å°æ‹¬å·é‡Œæ‰“å°æ•°å—(%d)没有任何价值,应该é¿å…è¿™æ ·åšã€‚ + +<linux/device.h>里有一些驱动模型诊æ–å®ï¼Œä½ 应该使用它们,以确ä¿ä¿¡æ¯å¯¹åº”于æ£ç¡®çš„ +è®¾å¤‡å’Œé©±åŠ¨ï¼Œå¹¶ä¸”è¢«æ ‡è®°äº†æ£ç¡®çš„消æ¯çº§åˆ«ã€‚这些å®æœ‰ï¼šdev_err(), dev_warn(), +dev_info()ç‰ç‰ã€‚对于那些ä¸å’ŒæŸä¸ªç‰¹å®šè®¾å¤‡ç›¸å…³è¿žçš„ä¿¡æ¯ï¼Œ<linux/kernel.h>定义了 +pr_debug()å’Œpr_info()。 + +写出好的调试信æ¯å¯ä»¥æ˜¯ä¸€ä¸ªå¾ˆå¤§çš„æŒ‘æˆ˜ï¼›å½“ä½ å†™å‡ºæ¥ä¹‹åŽï¼Œè¿™äº›ä¿¡æ¯åœ¨è¿œç¨‹é™¤é”™çš„时候 +就会æˆä¸ºæžå¤§çš„帮助。当DEBUG符å·æ²¡æœ‰è¢«å®šä¹‰çš„时候,这些信æ¯ä¸åº”è¯¥è¢«ç¼–è¯‘è¿›å†…æ ¸é‡Œ +(也就是说,默认地,它们ä¸åº”该被包å«åœ¨å†…ï¼‰ã€‚å¦‚æžœä½ ä½¿ç”¨dev_dbg()或者pr_debug(), +就能自动达到这个效果。很多å系统拥有Kconfig选项æ¥å¯ç”¨-DDEBUG。还有一个相关的惯例 +是使用VERBOSE_DEBUGæ¥æ·»åŠ dev_vdbg()消æ¯åˆ°é‚£äº›å·²ç»ç”±DEBUGå¯ç”¨çš„消æ¯ä¹‹ä¸Šã€‚ + + + 第åå››ç« ï¼šåˆ†é…å†…å˜ + +å†…æ ¸æ供了下é¢çš„一般用途的内å˜åˆ†é…函数:kmalloc(),kzalloc(),kcalloc()å’Œ +vmalloc()。请å‚考API文档以获å–有关它们的详细信æ¯ã€‚ + +ä¼ é€’ç»“æž„ä½“å¤§å°çš„首选形å¼æ˜¯è¿™æ ·çš„: + + p = kmalloc(sizeof(*p), ...); + +å¦å¤–一ç§ä¼ 递方å¼ä¸ï¼Œsizeofçš„æ“作数是结构体的åå—ï¼Œè¿™æ ·ä¼šé™ä½Žå¯è¯»æ€§ï¼Œå¹¶ä¸”å¯èƒ½ä¼šå¼• +å…¥bug。有å¯èƒ½æŒ‡é’ˆå˜é‡ç±»åž‹è¢«æ”¹å˜æ—¶ï¼Œè€Œå¯¹åº”çš„ä¼ é€’ç»™å†…å˜åˆ†é…函数的sizeof的结果ä¸å˜ã€‚ + +强制转æ¢ä¸€ä¸ªvoid指针返回值是多余的。Cè¯è¨€æœ¬èº«ä¿è¯äº†ä»Žvoid指针到其他任何指针类型 +的转æ¢æ˜¯æ²¡æœ‰é—®é¢˜çš„。 + + + 第åäº”ç« ï¼šå†…è”弊病 + +有一个常è§çš„误解是内è”函数是gccæ供的å¯ä»¥è®©ä»£ç è¿è¡Œæ›´å¿«çš„ä¸€ä¸ªé€‰é¡¹ã€‚è™½ç„¶ä½¿ç”¨å†…è” +函数有时候是æ°å½“的(比如作为一ç§æ›¿ä»£å®çš„æ–¹å¼ï¼Œè¯·çœ‹ç¬¬åäºŒç« ï¼‰ï¼Œä¸è¿‡å¾ˆå¤šæƒ…况下ä¸æ˜¯ +è¿™æ ·ã€‚inline关键å—çš„è¿‡åº¦ä½¿ç”¨ä¼šä½¿å†…æ ¸å˜å¤§ï¼Œä»Žè€Œä½¿æ•´ä¸ªç³»ç»Ÿè¿è¡Œé€Ÿåº¦å˜æ…¢ã€‚å› ä¸ºå¤§å†…æ ¸ +会å 用更多的指令高速缓å˜ï¼ˆè¯‘注:一级缓å˜é€šå¸¸æ˜¯æŒ‡ä»¤ç¼“å˜å’Œæ•°æ®ç¼“å˜åˆ†å¼€çš„)而且会导 +致pagecacheçš„å¯ç”¨å†…å˜å‡å°‘。想象一下,一次pagecache未命ä¸å°±ä¼šå¯¼è‡´ä¸€æ¬¡ç£ç›˜å¯»å€ï¼Œå°† +耗时5毫秒。5毫秒的时间内CPU能执行很多很多指令。 + +一个基本的原则是如果一个函数有3行以上,就ä¸è¦æŠŠå®ƒå˜æˆå†…è”函数。这个原则的一个例 +å¤–æ˜¯ï¼Œå¦‚æžœä½ çŸ¥é“æŸä¸ªå‚数是一个编译时常é‡ï¼Œè€Œä¸”å› ä¸ºè¿™ä¸ªå¸¸é‡ä½ 确定编译器在编译时能 +ä¼˜åŒ–æŽ‰ä½ çš„å‡½æ•°çš„å¤§éƒ¨åˆ†ä»£ç ,那ä»ç„¶å¯ä»¥ç»™å®ƒåŠ 上inline关键å—。kmalloc()内è”函数就 +是一个很好的例å。 + +人们ç»å¸¸ä¸»å¼ ç»™static的而且åªç”¨äº†ä¸€æ¬¡çš„å‡½æ•°åŠ ä¸Šinline,如æ¤ä¸ä¼šæœ‰ä»»ä½•æŸå¤±ï¼Œå› 为没 +有什么好æƒè¡¡çš„。虽然从技术上说这是æ£ç¡®çš„,但是实际上这ç§æƒ…况下å³ä½¿ä¸åŠ inline gcc +也å¯ä»¥è‡ªåŠ¨ä½¿å…¶å†…è”。而且其他用户å¯èƒ½ä¼šè¦æ±‚移除inline,由æ¤è€Œæ¥çš„争论会抵消inline +自身的潜在价值,得ä¸å¿å¤±ã€‚ + + + 第åå…ç« ï¼šå‡½æ•°è¿”å›žå€¼åŠå‘½å + +函数å¯ä»¥è¿”回很多ç§ä¸åŒç±»åž‹çš„值,最常è§çš„一ç§æ˜¯è¡¨æ˜Žå‡½æ•°æ‰§è¡ŒæˆåŠŸæˆ–è€…å¤±è´¥çš„å€¼ã€‚è¿™æ · +的一个值å¯ä»¥è¡¨ç¤ºä¸ºä¸€ä¸ªé”™è¯¯ä»£ç 整数(-Exxxï¼å¤±è´¥ï¼Œ0ï¼æˆåŠŸï¼‰æˆ–者一个“æˆåŠŸâ€å¸ƒå°”值( +0ï¼å¤±è´¥ï¼Œéž0ï¼æˆåŠŸï¼‰ã€‚ + +æ··åˆä½¿ç”¨è¿™ä¸¤ç§è¡¨è¾¾æ–¹å¼æ˜¯éš¾äºŽå‘现的bugçš„æ¥æºã€‚如果Cè¯è¨€æœ¬èº«ä¸¥æ ¼åŒºåˆ†æ•´å½¢å’Œå¸ƒå°”åž‹å˜ +é‡ï¼Œé‚£ä¹ˆç¼–译器就能够帮我们å‘现这些错误……ä¸è¿‡Cè¯è¨€ä¸åŒºåˆ†ã€‚为了é¿å…产生这ç§bug,请 +éµå¾ªä¸‹é¢çš„惯例: + + 如果函数的åå—是一个动作或者强制性的命令,那么这个函数应该返回错误代ç æ•´ + 数。如果是一个判æ–,那么函数应该返回一个“æˆåŠŸâ€å¸ƒå°”值。 + +比如,“add workâ€æ˜¯ä¸€ä¸ªå‘½ä»¤ï¼Œæ‰€ä»¥add_work()函数在æˆåŠŸæ—¶è¿”回0,在失败时返回-EBUSY。 +ç±»ä¼¼çš„ï¼Œå› ä¸ºâ€œPCI device presentâ€æ˜¯ä¸€ä¸ªåˆ¤æ–,所以pci_dev_present()函数在æˆåŠŸæ‰¾åˆ° +一个匹é…的设备时应该返回1,如果找ä¸åˆ°æ—¶åº”该返回0。 + +所有导出(译注:EXPORT)的函数都必须éµå®ˆè¿™ä¸ªæƒ¯ä¾‹ï¼Œæ‰€æœ‰çš„公共函数也都应该如æ¤ã€‚ç§ +有(static)函数ä¸éœ€è¦å¦‚æ¤ï¼Œä½†æ˜¯æˆ‘们也推èè¿™æ ·åšã€‚ + +返回值是实际计算结果而ä¸æ˜¯è®¡ç®—是å¦æˆåŠŸçš„æ ‡å¿—çš„å‡½æ•°ä¸å—æ¤æƒ¯ä¾‹çš„é™åˆ¶ã€‚一般的,他们 +通过返回一些æ£å¸¸å€¼èŒƒå›´ä¹‹å¤–的结果æ¥è¡¨ç¤ºå‡ºé”™ã€‚典型的例å是返回指针的函数,他们使用 +NULL或者ERR_PTR机制æ¥æŠ¥å‘Šé”™è¯¯ã€‚ + + + 第åä¸ƒç« ï¼šä¸è¦é‡æ–°å‘æ˜Žå†…æ ¸å® + +头文件include/linux/kernel.h包å«äº†ä¸€äº›å®ï¼Œä½ 应该使用它们,而ä¸è¦è‡ªå·±å†™ä¸€äº›å®ƒä»¬çš„ +å˜ç§ã€‚æ¯”å¦‚ï¼Œå¦‚æžœä½ éœ€è¦è®¡ç®—ä¸€ä¸ªæ•°ç»„çš„é•¿åº¦ï¼Œä½¿ç”¨è¿™ä¸ªå® + + #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +ç±»ä¼¼çš„ï¼Œå¦‚æžœä½ è¦è®¡ç®—æŸç»“构体æˆå‘˜çš„大å°ï¼Œä½¿ç”¨ + + #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) + +还有å¯ä»¥åšä¸¥æ ¼çš„类型检查的min()å’Œmax()å®ï¼Œå¦‚æžœä½ éœ€è¦å¯ä»¥ä½¿ç”¨å®ƒä»¬ã€‚ä½ å¯ä»¥è‡ªå·±çœ‹çœ‹ +é‚£ä¸ªå¤´æ–‡ä»¶é‡Œè¿˜å®šä¹‰äº†ä»€ä¹ˆä½ å¯ä»¥æ‹¿æ¥ç”¨çš„东西,如果有定义的è¯ï¼Œä½ å°±ä¸åº”åœ¨ä½ çš„ä»£ç 里 +自己é‡æ–°å®šä¹‰ã€‚ + + + 第åå…«ç« ï¼šç¼–è¾‘å™¨æ¨¡å¼è¡Œå’Œå…¶ä»–需è¦ç½—嗦的事情 + +有一些编辑器å¯ä»¥è§£é‡ŠåµŒå…¥åœ¨æºæ–‡ä»¶é‡Œçš„ç”±ä¸€äº›ç‰¹æ®Šæ ‡è®°æ ‡æ˜Žçš„é…置信æ¯ã€‚比如,emacs +èƒ½å¤Ÿè§£é‡Šè¢«æ ‡è®°æˆè¿™æ ·çš„行: + +-*- mode: c -*- + +æˆ–è€…è¿™æ ·çš„ï¼š + +/* +Local Variables: +compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c" +End: +*/ + +Vimèƒ½å¤Ÿè§£é‡Šè¿™æ ·çš„æ ‡è®°ï¼š + +/* vim:set sw=8 noet */ + +ä¸è¦åœ¨æºä»£ç ä¸åŒ…å«ä»»ä½•è¿™æ ·çš„内容。æ¯ä¸ªäººéƒ½æœ‰ä»–自己的编辑器é…ç½®ï¼Œä½ çš„æºæ–‡ä»¶ä¸åº” +该覆盖别人的é…置。这包括有关缩进和模å¼é…ç½®çš„æ ‡è®°ã€‚äººä»¬å¯ä»¥ä½¿ç”¨ä»–们自己定制的模 +å¼ï¼Œæˆ–者使用其他å¯ä»¥äº§ç”Ÿæ£ç¡®çš„缩进的巧妙方法。 + + + + 附录 I:å‚考 + +The C Programming Language, 第二版, 作者Brian W. Kernighanå’ŒDenni +M. Ritchie. Prentice Hall, Inc., 1988. ISBN 0-13-110362-8 (软皮), +0-13-110370-9 (硬皮). URL: http://cm.bell-labs.com/cm/cs/cbook/ + +The Practice of Programming 作者Brian W. Kernighanå’ŒRob Pike. Addison-Wesley, +Inc., 1999. ISBN 0-201-61586-X. URL: http://cm.bell-labs.com/cm/cs/tpop/ + +cpp,gcc,gcc internalså’Œindentçš„GNU手册——和K&RåŠæœ¬æ–‡ç›¸ç¬¦åˆçš„部分,全部å¯ä»¥åœ¨ +http://www.gnu.org/manual/找到 + +WG14是Cè¯è¨€çš„å›½é™…æ ‡å‡†åŒ–å·¥ä½œç»„ï¼ŒURL: http://www.open-std.org/JTC1/SC22/WG14/ + +Kernel CodingStyle,作者greg@kroah.comå‘表于OLS 2002: +http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/ + +-- +最åŽæ›´æ–°äºŽ2007å¹´7月13日。 diff --git a/Documentation/zh_CN/HOWTO b/Documentation/zh_CN/HOWTO index 48fc67bfbe3d33a8c04817db587a107d29e09177..3d80e8af36eced538ba0dde705ac0302435b04c3 100644 --- a/Documentation/zh_CN/HOWTO +++ b/Documentation/zh_CN/HOWTO @@ -1,10 +1,10 @@ Chinese translated version of Documentation/HOWTO If you have any comment or update to the content, please contact the -original document maintainer directly. However, if you have problem +original document maintainer directly. However, if you have a problem communicating in English you can also ask the Chinese maintainer for -help. Contact the Chinese maintainer, if this translation is outdated -or there is problem with translation. +help. Contact the Chinese maintainer if this translation is outdated +or if there is a problem with the translation. Maintainer: Greg Kroah-Hartman <greg@kroah.com> Chinese maintainer: Li Yang <leoli@freescale.com> @@ -85,7 +85,7 @@ Linuxå†…æ ¸æºä»£ç 都是在GPL(通用公共许å¯è¯ï¼‰çš„ä¿æŠ¤ä¸‹å‘布的 Linuxå†…æ ¸ä»£ç ä¸åŒ…å«æœ‰å¤§é‡çš„文档。这些文档对于å¦ä¹ å¦‚ä½•ä¸Žå†…æ ¸ç¤¾åŒºäº’åŠ¨æœ‰ç€ ä¸å¯ä¼°é‡çš„ä»·å€¼ã€‚å½“ä¸€ä¸ªæ–°çš„åŠŸèƒ½è¢«åŠ å…¥å†…æ ¸ï¼Œæœ€å¥½æŠŠè§£é‡Šå¦‚ä½•ä½¿ç”¨è¿™ä¸ªåŠŸèƒ½çš„æ–‡ æ¡£ä¹Ÿæ”¾è¿›å†…æ ¸ã€‚å½“å†…æ ¸çš„æ”¹åŠ¨å¯¼è‡´é¢å‘用户空间的接å£å‘生å˜åŒ–时,最好将相关信 -æ¯æˆ–手册页(manpages)çš„è¡¥ä¸å‘到mtk-manpages@gmx.net,以å‘手册页(manpages) +æ¯æˆ–手册页(manpages)çš„è¡¥ä¸å‘到mtk.manpages@gmail.com,以å‘手册页(manpages) 的维护者解释这些å˜åŒ–。 ä»¥ä¸‹æ˜¯å†…æ ¸ä»£ç ä¸éœ€è¦é˜…读的文档: @@ -218,6 +218,8 @@ kernel.org网站的pub/linux/kernel/v2.6/目录下找到它。它的开å‘éµå¾ª 时,一个新的-rc版本就会被å‘布。计划是æ¯å‘¨éƒ½å‘布新的-rc版本。 - 这个过程一直æŒç»ä¸‹åŽ»ç›´åˆ°å†…æ ¸è¢«è®¤ä¸ºè¾¾åˆ°è¶³å¤Ÿç¨³å®šçš„çŠ¶æ€ï¼ŒæŒç»æ—¶é—´å¤§æ¦‚是 6个星期。 + - 以下地å€è·Ÿè¸ªäº†åœ¨æ¯ä¸ª-rcå‘布ä¸å‘现的退æ¥åˆ—表: + http://kernelnewbies.org/known_regressions å…³äºŽå†…æ ¸å‘布,值得一æ的是Andrew Morton在linux-kernel邮件列表ä¸å¦‚是说: “没有人知é“æ–°å†…æ ¸ä½•æ—¶ä¼šè¢«å‘å¸ƒï¼Œå› ä¸ºå‘å¸ƒæ˜¯æ ¹æ®å·²çŸ¥bug的情况æ¥å†³å®š diff --git a/Documentation/zh_CN/SubmittingDrivers b/Documentation/zh_CN/SubmittingDrivers new file mode 100644 index 0000000000000000000000000000000000000000..5f4815c63ec7b55cde300abbf3232a399a504fd3 --- /dev/null +++ b/Documentation/zh_CN/SubmittingDrivers @@ -0,0 +1,168 @@ +Chinese translated version of Documentation/SubmittingDrivers + +If you have any comment or update to the content, please contact the +original document maintainer directly. However, if you have a problem +communicating in English you can also ask the Chinese maintainer for +help. Contact the Chinese maintainer if this translation is outdated +or if there is a problem with the translation. + +Chinese maintainer: Li Yang <leo@zh-kernel.org> +--------------------------------------------------------------------- +Documentation/SubmittingDrivers çš„ä¸æ–‡ç¿»è¯‘ + +如果想评论或更新本文的内容,请直接è”ç³»åŽŸæ–‡æ¡£çš„ç»´æŠ¤è€…ã€‚å¦‚æžœä½ ä½¿ç”¨è‹±æ–‡ +交æµæœ‰å›°éš¾çš„è¯ï¼Œä¹Ÿå¯ä»¥å‘ä¸æ–‡ç‰ˆç»´æŠ¤è€…求助。如果本翻译更新ä¸åŠæ—¶æˆ–者翻 +译å˜åœ¨é—®é¢˜ï¼Œè¯·è”ç³»ä¸æ–‡ç‰ˆç»´æŠ¤è€…。 + +ä¸æ–‡ç‰ˆç»´æŠ¤è€…: æŽé˜³ Li Yang <leo@zh-kernel.org> +ä¸æ–‡ç‰ˆç¿»è¯‘者: æŽé˜³ Li Yang <leo@zh-kernel.org> +ä¸æ–‡ç‰ˆæ ¡è¯‘者: é™ˆç¦ Maggie Chen <chenqi@beyondsoft.com> + çŽ‹èª Wang Cong <xiyou.wangcong@gmail.com> + å¼ å· Zhang Wei <Wei.Zhang@freescale.com> + +以下为æ£æ–‡ +--------------------------------------------------------------------- + +å¦‚ä½•å‘ Linux å†…æ ¸æäº¤é©±åŠ¨ç¨‹åº +----------------------------- + +这篇文档将会解释如何å‘ä¸åŒçš„å†…æ ¸æºç æ ‘æ交设备驱动程åºã€‚请注æ„ï¼Œå¦‚æžœä½ æ„Ÿ +兴趣的是显å¡é©±åŠ¨ç¨‹åºï¼Œä½ 也许应该访问 XFree86 项目(http://www.xfree86.org/) +å’Œï¼æˆ– X.org 项目 (http://x.org)。 + +å¦è¯·å‚阅 Documentation/SubmittingPatches 文档。 + + +分é…è®¾å¤‡å· +---------- + +å—设备和å—符设备的主设备å·ä¸Žä»Žè®¾å¤‡å·æ˜¯ç”± Linux 命åç¼–å·åˆ†é…æƒå¨ LANANA( +现在是 Torben Mathiasen)负责分é…。申请的网å€æ˜¯ http://www.lanana.org/。 +å³ä½¿ä¸å‡†å¤‡æ交到主æµå†…æ ¸çš„è®¾å¤‡é©±åŠ¨ä¹Ÿéœ€è¦åœ¨è¿™é‡Œåˆ†é…设备å·ã€‚有关详细信æ¯ï¼Œ +请å‚阅 Documentation/devices.txt。 + +å¦‚æžœä½ ä½¿ç”¨çš„ä¸æ˜¯å·²ç»åˆ†é…的设备å·ï¼Œé‚£ä¹ˆå½“ä½ æ交设备驱动的时候,它将会被强 +制分é…一个新的设备å·ï¼Œå³ä¾¿è¿™ä¸ªè®¾å¤‡å·å’Œä½ 之å‰å‘给客户的截然ä¸åŒã€‚ + +设备驱动的æ交对象 +------------------ + +Linux 2.0: + æ¤å†…æ ¸æºç æ ‘ä¸æŽ¥å—新的驱动程åºã€‚ + +Linux 2.2: + æ¤å†…æ ¸æºç æ ‘ä¸æŽ¥å—新的驱动程åºã€‚ + +Linux 2.4: + 如果所属的代ç é¢†åŸŸåœ¨å†…æ ¸çš„ MAINTAINERS 文件ä¸åˆ—有一个总维护者, + 那么请将驱动程åºæ交给他。如果æ¤ç»´æŠ¤è€…æ²¡æœ‰å›žåº”æˆ–è€…ä½ æ‰¾ä¸åˆ°æ°å½“çš„ + 维护者,那么请è”ç³» Willy Tarreau <w@1wt.eu>。 + +Linux 2.6: + 除了éµå¾ªå’Œ 2.4 ç‰ˆå†…æ ¸åŒæ ·çš„è§„åˆ™å¤–ï¼Œä½ è¿˜éœ€è¦åœ¨ linux-kernel 邮件 + 列表上跟踪最新的 API å˜åŒ–ã€‚å‘ Linux 2.6 å†…æ ¸æ交驱动的顶级è”系人 + 是 Andrew Morton <akpm@osdl.org>。 + +决定设备驱动能å¦è¢«æŽ¥å—çš„æ¡ä»¶ +---------------------------- + +许å¯ï¼š 代ç 必须使用 GNU 通用公开许å¯è¯ (GPL) æ交给 Linux,但是 + 我们并ä¸è¦æ±‚ GPL 是唯一的许å¯ã€‚ä½ æˆ–è®¸ä¼šå¸Œæœ›åŒæ—¶ä½¿ç”¨å¤šç§ + 许å¯è¯å‘布,如果希望驱动程åºå¯ä»¥è¢«å…¶ä»–å¼€æºç¤¾åŒºï¼ˆæ¯”如BSD) + 使用。请å‚考 include/linux/module.h 文件ä¸æ‰€åˆ—出的å¯è¢« + 接å—å…±å˜çš„许å¯ã€‚ + +版æƒï¼š 版æƒæ‰€æœ‰è€…å¿…é¡»åŒæ„使用 GPL 许å¯ã€‚最好æ交者和版æƒæ‰€æœ‰è€… + 是相åŒä¸ªäººæˆ–实体。å¦åˆ™ï¼Œå¿…需列出授æƒä½¿ç”¨ GPL 的版æƒæ‰€æœ‰ + 人或实体,以备验è¯ä¹‹éœ€ã€‚ + +接å£ï¼š å¦‚æžœä½ çš„é©±åŠ¨ç¨‹åºä½¿ç”¨çŽ°æˆçš„接å£å¹¶ä¸”和其他åŒç±»çš„驱动程åºè¡Œ + 为相似,而ä¸æ˜¯åŽ»å‘æ˜Žæ— è°“çš„æ–°æŽ¥å£ï¼Œé‚£ä¹ˆå®ƒå°†ä¼šæ›´å®¹æ˜“被接å—。 + å¦‚æžœä½ éœ€è¦ä¸€ä¸ª Linux å’Œ NT 的通用驱动接å£ï¼Œé‚£ä¹ˆè¯·åœ¨ç”¨ + 户空间实现它。 + +代ç : 请使用 Documentation/CodingStyle ä¸æ‰€æè¿°çš„ Linux 代ç 风 + æ ¼ã€‚å¦‚æžœä½ çš„æŸäº›ä»£ç 段(例如那些与 Windows 驱动程åºåŒ…å…± + 享的代ç 段)需è¦ä½¿ç”¨å…¶ä»–æ ¼å¼ï¼Œè€Œä½ å´åªå¸Œæœ›ç»´æŠ¤ä¸€ä»½ä»£ç , + 那么请将它们很好地区分出æ¥ï¼Œå¹¶ä¸”æ³¨æ˜ŽåŽŸå› ã€‚ + +å¯ç§»æ¤æ€§ï¼š 请注æ„,指针并ä¸æ°¸è¿œæ˜¯ 32 ä½çš„,ä¸æ˜¯æ‰€æœ‰çš„è®¡ç®—æœºéƒ½ä½¿ç”¨å° + å°¾æ¨¡å¼ (little endian) å˜å‚¨æ•°æ®ï¼Œä¸æ˜¯æ‰€æœ‰çš„人都拥有浮点 + å•å…ƒï¼Œä¸è¦éšä¾¿åœ¨ä½ 的驱动程åºé‡ŒåµŒå…¥ x86 汇编指令。åªèƒ½åœ¨ + x86 上è¿è¡Œçš„驱动程åºä¸€èˆ¬æ˜¯ä¸å—æ¬¢è¿Žçš„ã€‚è™½ç„¶ä½ å¯èƒ½åªæœ‰ x86 + 硬件,很难测试驱动程åºåœ¨å…¶ä»–å¹³å°ä¸Šæ˜¯å¦å¯ç”¨ï¼Œä½†æ˜¯ç¡®ä¿ä»£ç + å¯ä»¥è¢«è½»æ¾åœ°ç§»æ¤å´æ˜¯å¾ˆç®€å•çš„。 + +清晰度: åšåˆ°æ‰€æœ‰äººéƒ½èƒ½ä¿®è¡¥è¿™ä¸ªé©±åŠ¨ç¨‹åºå°†ä¼šå¾ˆæœ‰å¥½å¤„ï¼Œå› ä¸ºè¿™æ ·ä½ å°† + 会直接收到修å¤çš„è¡¥ä¸è€Œä¸æ˜¯ bug æŠ¥å‘Šã€‚å¦‚æžœä½ æ交一个试图 + éšè—硬件工作机ç†çš„驱动程åºï¼Œé‚£ä¹ˆå®ƒå°†ä¼šè¢«æ‰”进废纸篓。 + +电æºç®¡ç†ï¼š å› ä¸º Linux æ£åœ¨è¢«å¾ˆå¤šç§»åŠ¨è®¾å¤‡å’Œæ¡Œé¢ç³»ç»Ÿä½¿ç”¨ï¼Œæ‰€ä»¥ä½ 的驱 + 动程åºä¹Ÿå¾ˆæœ‰å¯èƒ½è¢«ä½¿ç”¨åœ¨è¿™äº›è®¾å¤‡ä¸Šã€‚它应该支æŒæœ€åŸºæœ¬çš„电 + æºç®¡ç†ï¼Œå³åœ¨éœ€è¦çš„æƒ…å†µä¸‹å®žçŽ°ç³»ç»Ÿçº§ä¼‘çœ å’Œå”¤é†’è¦ç”¨åˆ°çš„ + .suspend å’Œ .resume å‡½æ•°ã€‚ä½ åº”è¯¥æ£€æŸ¥ä½ çš„é©±åŠ¨ç¨‹åºæ˜¯å¦èƒ½æ£ + 确地处ç†ä¼‘çœ ä¸Žå”¤é†’ï¼Œå¦‚æžœå®žåœ¨æ— æ³•ç¡®è®¤ï¼Œè¯·è‡³å°‘æŠŠ .suspend + 函数定义æˆè¿”回 -ENOSYSï¼ˆåŠŸèƒ½æœªå®žçŽ°ï¼‰é”™è¯¯ã€‚ä½ è¿˜åº”è¯¥å°è¯•ç¡® + ä¿ä½ 的驱动在什么都ä¸å¹²çš„情况下将耗电é™åˆ°æœ€ä½Žã€‚è¦èŽ·å¾—驱动 + 程åºæµ‹è¯•çš„指导,请å‚阅 + Documentation/power/drivers-testing.txt。有关驱动程åºç”µ + æºç®¡ç†é—®é¢˜ç›¸å¯¹å…¨é¢çš„概述,请å‚阅 + Documentation/power/devices.txt。 + +管ç†ï¼š 如果一个驱动程åºçš„作者还在进行有效的维护,那么通常除了那 + 些明显æ£ç¡®ä¸”ä¸éœ€è¦ä»»ä½•æ£€æŸ¥çš„è¡¥ä¸ä»¥å¤–,其他所有的补ä¸éƒ½ä¼š + 被转å‘ç»™ä½œè€…ã€‚å¦‚æžœä½ å¸Œæœ›æˆä¸ºé©±åŠ¨ç¨‹åºçš„è”系人和更新者,最 + 好在代ç 注释ä¸å†™æ˜Žå¹¶ä¸”在 MAINTAINERS 文件ä¸åŠ 入这个驱动 + 程åºçš„æ¡ç›®ã€‚ + +ä¸å½±å“设备驱动能å¦è¢«æŽ¥å—çš„æ¡ä»¶ +------------------------------ + +供应商: 由硬件供应商æ¥ç»´æŠ¤é©±åŠ¨ç¨‹åºé€šå¸¸æ˜¯ä¸€ä»¶å¥½äº‹ã€‚ä¸è¿‡ï¼Œå¦‚æžœæºç + æ ‘é‡Œå·²ç»æœ‰å…¶ä»–人æ供了å¯ç¨³å®šå·¥ä½œçš„驱动程åºï¼Œé‚£ä¹ˆè¯·ä¸è¦æœŸ + 望“我是供应商â€ä¼šæˆä¸ºå†…æ ¸æ”¹ç”¨ä½ çš„é©±åŠ¨ç¨‹åºçš„ç†ç”±ã€‚ç†æƒ³çš„情 + 况是:供应商与现有驱动程åºçš„作者åˆä½œï¼Œæž„建一个统一完美的 + 驱动程åºã€‚ + +作者: 驱动程åºæ˜¯ç”±å¤§çš„ Linux å…¬å¸ç ”å‘è¿˜æ˜¯ç”±ä½ ä¸ªäººç¼–å†™ï¼Œå¹¶ä¸å½± + å“其是å¦èƒ½è¢«å†…æ ¸æŽ¥å—ã€‚æ²¡æœ‰äººå¯¹å†…æ ¸æºç æ ‘äº«æœ‰ç‰¹æƒã€‚åªè¦ä½ + å……åˆ†äº†è§£å†…æ ¸ç¤¾åŒºï¼Œä½ å°±ä¼šå‘现这一点。 + + +资æºåˆ—表 +-------- + +Linux å†…æ ¸ä¸»æºç æ ‘ï¼š + ftp.??.kernel.org:/pub/linux/kernel/... + ?? == ä½ çš„å›½å®¶ä»£ç ,例如 "cn"ã€"us"ã€"uk"ã€"fr" ç‰ç‰ + +Linux å†…æ ¸é‚®ä»¶åˆ—è¡¨ï¼š + linux-kernel@vger.kernel.org + [å¯é€šè¿‡å‘majordomo@vger.kernel.orgå‘邮件æ¥è®¢é˜…] + +Linux 设备驱动程åºï¼Œç¬¬ä¸‰ç‰ˆï¼ˆæŽ¢è®¨ 2.6.10 ç‰ˆå†…æ ¸ï¼‰ï¼š + http://lwn.net/Kernel/LDD3/ (å…费版) + +LWN.net: + æ¯å‘¨å†…æ ¸å¼€å‘æ´»åŠ¨æ‘˜è¦ - http://lwn.net/ + 2.6 ç‰ˆä¸ API çš„å˜æ›´ï¼š + http://lwn.net/Articles/2.6-kernel-api/ + å°†æ—§ç‰ˆå†…æ ¸çš„é©±åŠ¨ç¨‹åºç§»æ¤åˆ° 2.6 版: + http://lwn.net/Articles/driver-porting/ + +KernelTrap: + Linux å†…æ ¸çš„æœ€æ–°åŠ¨æ€ä»¥åŠå¼€å‘者访谈 + http://kerneltrap.org/ + +å†…æ ¸æ–°æ‰‹(KernelNewbies): + ä¸ºæ–°çš„å†…æ ¸å¼€å‘者æ供文档和帮助 + http://kernelnewbies.org/ + +Linux USB项目: + http://www.linux-usb.org/ + +å†™å†…æ ¸é©±åŠ¨çš„â€œä¸è¦â€ï¼ˆArjan van de Ven著): + http://www.fenrus.org/how-to-not-write-a-device-driver-paper.pdf + +å†…æ ¸æ¸…æ´å·¥ (Kernel Janitor): + http://janitor.kernelnewbies.org/ diff --git a/Documentation/zh_CN/SubmittingPatches b/Documentation/zh_CN/SubmittingPatches new file mode 100644 index 0000000000000000000000000000000000000000..985c92e20b738a94d244342e736caac89a24d170 --- /dev/null +++ b/Documentation/zh_CN/SubmittingPatches @@ -0,0 +1,416 @@ +Chinese translated version of Documentation/SubmittingPatches + +If you have any comment or update to the content, please contact the +original document maintainer directly. However, if you have a problem +communicating in English you can also ask the Chinese maintainer for +help. Contact the Chinese maintainer if this translation is outdated +or if there is a problem with the translation. + +Chinese maintainer: TripleX Chung <triplex@zh-kernel.org> +--------------------------------------------------------------------- +Documentation/SubmittingPatches çš„ä¸æ–‡ç¿»è¯‘ + +如果想评论或更新本文的内容,请直接è”ç³»åŽŸæ–‡æ¡£çš„ç»´æŠ¤è€…ã€‚å¦‚æžœä½ ä½¿ç”¨è‹±æ–‡ +交æµæœ‰å›°éš¾çš„è¯ï¼Œä¹Ÿå¯ä»¥å‘ä¸æ–‡ç‰ˆç»´æŠ¤è€…求助。如果本翻译更新ä¸åŠæ—¶æˆ–者翻 +译å˜åœ¨é—®é¢˜ï¼Œè¯·è”ç³»ä¸æ–‡ç‰ˆç»´æŠ¤è€…。 + +ä¸æ–‡ç‰ˆç»´æŠ¤è€…: 钟宇 TripleX Chung <triplex@zh-kernel.org> +ä¸æ–‡ç‰ˆç¿»è¯‘者: 钟宇 TripleX Chung <triplex@zh-kernel.org> +ä¸æ–‡ç‰ˆæ ¡è¯‘者: æŽé˜³ Li Yang <leo@zh-kernel.org> + çŽ‹èª Wang Cong <xiyou.wangcong@gmail.com> + +以下为æ£æ–‡ +--------------------------------------------------------------------- + + å¦‚ä½•è®©ä½ çš„æ”¹åŠ¨è¿›å…¥å†…æ ¸ + 或者 + 获得亲爱的 Linus Torvalds çš„å…³æ³¨å’Œå¤„ç† +---------------------------------- + +对于想è¦å°†æ”¹åŠ¨æ交到 Linux å†…æ ¸çš„ä¸ªäººæˆ–è€…å…¬å¸æ¥è¯´ï¼Œå¦‚æžœä¸ç†Ÿæ‚‰â€œè§„矩â€ï¼Œ +æ交的æµç¨‹ä¼šè®©äººç•æƒ§ã€‚本文档收集了一系列建议,这些建议å¯ä»¥å¤§å¤§çš„æé«˜ä½ +的改动被接å—的机会。 +阅读 Documentation/SubmitChecklist æ¥èŽ·å¾—在æ交代ç å‰éœ€è¦æ£€æŸ¥çš„项目的列 +è¡¨ã€‚å¦‚æžœä½ åœ¨æ交一个驱动程åºï¼Œé‚£ä¹ˆåŒæ—¶é˜…读一下 +Documentation/SubmittingDrivers 。 + + +-------------------------- +第一节 - 创建并å‘é€ä½ 的改动 +-------------------------- + +1) "diff -up" +----------- + +使用 "diff -up" 或者 "diff -uprN" æ¥åˆ›å»ºè¡¥ä¸ã€‚ + +æ‰€æœ‰å†…æ ¸çš„æ”¹åŠ¨ï¼Œéƒ½æ˜¯ä»¥è¡¥ä¸çš„å½¢å¼å‘ˆçŽ°çš„,补ä¸ç”± diff(1) 生æˆã€‚创建补ä¸çš„ +时候,è¦ç¡®è®¤å®ƒæ˜¯ä»¥ "unified diff" æ ¼å¼åˆ›å»ºçš„,这ç§æ ¼å¼ç”± diff(1) çš„ '-u' +å‚数生æˆã€‚而且,请使用 '-p' å‚æ•°ï¼Œé‚£æ ·ä¼šæ˜¾ç¤ºæ¯ä¸ªæ”¹åŠ¨æ‰€åœ¨çš„C函数,使得 +产生的补ä¸å®¹æ˜“读得多。补ä¸åº”è¯¥åŸºäºŽå†…æ ¸æºä»£ç æ ‘çš„æ ¹ç›®å½•ï¼Œè€Œä¸æ˜¯é‡Œè¾¹çš„ä»» +何å目录。 +为一个å•ç‹¬çš„文件创建补ä¸ï¼Œä¸€èˆ¬æ¥è¯´è¿™æ ·åšå°±å¤Ÿäº†ï¼š + + SRCTREE= linux-2.6 + MYFILE= drivers/net/mydriver.c + + cd $SRCTREE + cp $MYFILE $MYFILE.orig + vi $MYFILE # make your change + cd .. + diff -up $SRCTREE/$MYFILE{.orig,} > /tmp/patch + +为多个文件创建补ä¸ï¼Œä½ å¯ä»¥è§£å¼€ä¸€ä¸ªæ²¡æœ‰ä¿®æ”¹è¿‡çš„å†…æ ¸æºä»£ç æ ‘ï¼Œç„¶åŽå’Œä½ 自 +己的代ç æ ‘ä¹‹é—´åš diff 。例如: + + MYSRC= /devel/linux-2.6 + + tar xvfz linux-2.6.12.tar.gz + mv linux-2.6.12 linux-2.6.12-vanilla + diff -uprN -X linux-2.6.12-vanilla/Documentation/dontdiff \ + linux-2.6.12-vanilla $MYSRC > /tmp/patch + +"dontdiff" æ˜¯å†…æ ¸åœ¨ç¼–è¯‘çš„æ—¶å€™äº§ç”Ÿçš„æ–‡ä»¶çš„åˆ—è¡¨ï¼Œåˆ—è¡¨ä¸çš„文件在 diff(1) +产生的补ä¸é‡Œä¼šè¢«è·³è¿‡ã€‚"dontdiff" 文件被包å«åœ¨2.6.12和之åŽç‰ˆæœ¬çš„å†…æ ¸æºä»£ +ç æ ‘ä¸ã€‚å¯¹äºŽæ›´æ—©çš„å†…æ ¸ç‰ˆæœ¬ï¼Œä½ å¯ä»¥ä»Ž +<http://www.xenotime.net/linux/doc/dontdiff> 获å–它。 +ç¡®å®šä½ çš„è¡¥ä¸é‡Œæ²¡æœ‰åŒ…å«ä»»ä½•ä¸å±žäºŽè¿™æ¬¡è¡¥ä¸æ交的é¢å¤–文件。记得在用diff(1) +生æˆè¡¥ä¸ä¹‹åŽï¼Œå®¡é˜…一次补ä¸ï¼Œä»¥ç¡®ä¿å‡†ç¡®ã€‚ +å¦‚æžœä½ çš„æ”¹åŠ¨å¾ˆæ•£ä¹±ï¼Œä½ åº”è¯¥ç ”ç©¶ä¸€ä¸‹å¦‚ä½•å°†è¡¥ä¸åˆ†å‰²æˆç‹¬ç«‹çš„部分,将改动分 +割æˆä¸€ç³»åˆ—åˆä¹Žé€»è¾‘çš„æ¥éª¤ã€‚è¿™æ ·æ›´å®¹æ˜“è®©å…¶ä»–å†…æ ¸å¼€å‘è€…å®¡æ ¸ï¼Œå¦‚æžœä½ æƒ³ä½ çš„ +è¡¥ä¸è¢«æŽ¥å—,这是很é‡è¦çš„。下é¢è¿™äº›è„šæœ¬èƒ½å¤Ÿå¸®åŠ©ä½ åšè¿™ä»¶äº‹æƒ…: +Quilt: +http://savannah.nongnu.org/projects/quilt + +Andrew Morton çš„è¡¥ä¸è„šæœ¬: +http://www.zip.com.au/~akpm/linux/patches/ +作为这些脚本的替代,quilt 是值得推èçš„è¡¥ä¸ç®¡ç†å·¥å…·(看上é¢çš„链接)。 + +2)æè¿°ä½ çš„æ”¹åŠ¨ã€‚ +æè¿°ä½ çš„æ”¹åŠ¨åŒ…å«çš„技术细节。 + +è¦å¤šå…·ä½“就写多具体。最糟糕的æè¿°å¯èƒ½æ˜¯åƒä¸‹é¢è¿™äº›è¯å¥ï¼šâ€œæ›´æ–°äº†æŸé©±åŠ¨ç¨‹ +åºâ€ï¼Œâ€œä¿®æ£äº†æŸé©±åŠ¨ç¨‹åºçš„bugâ€ï¼Œæˆ–者“这个补ä¸åŒ…å«äº†æŸå系统的修改,请 +使用。†+ +å¦‚æžœä½ çš„æ述开始å˜é•¿ï¼Œè¿™è¡¨ç¤ºä½ 也许需è¦æ‹†åˆ†ä½ çš„è¡¥ä¸äº†ï¼Œè¯·çœ‹ç¬¬3å°èŠ‚, +继ç»ã€‚ + +3)æ‹†åˆ†ä½ çš„æ”¹åŠ¨ + +将改动拆分,逻辑类似的放到åŒä¸€ä¸ªè¡¥ä¸æ–‡ä»¶é‡Œã€‚ + +ä¾‹å¦‚ï¼Œå¦‚æžœä½ çš„æ”¹åŠ¨é‡ŒåŒæ—¶æœ‰bugä¿®æ£å’Œæ€§èƒ½ä¼˜åŒ–,那么把这些改动æ‰åˆ†åˆ°ä¸¤ä¸ªæˆ– +者更多的补ä¸æ–‡ä»¶ä¸ã€‚å¦‚æžœä½ çš„æ”¹åŠ¨åŒ…å«å¯¹API的修改,并且修改了驱动程åºæ¥é€‚ +应这些新的API,那么把这些修改分æˆä¸¤ä¸ªè¡¥ä¸ã€‚ + +å¦ä¸€æ–¹é¢ï¼Œå¦‚æžœä½ å°†ä¸€ä¸ªå•ç‹¬çš„改动åšæˆå¤šä¸ªè¡¥ä¸æ–‡ä»¶ï¼Œé‚£ä¹ˆå°†å®ƒä»¬åˆå¹¶æˆä¸€ä¸ª +å•ç‹¬çš„è¡¥ä¸æ–‡ä»¶ã€‚è¿™æ ·ä¸€ä¸ªé€»è¾‘ä¸Šå•ç‹¬çš„改动åªè¢«åŒ…å«åœ¨ä¸€ä¸ªè¡¥ä¸æ–‡ä»¶é‡Œã€‚ + +如果有一个补ä¸ä¾èµ–å¦å¤–一个补ä¸æ¥å®Œæˆå®ƒçš„改动,那没问题。简å•çš„åœ¨ä½ çš„è¡¥ +ä¸æ述里指出“这个补ä¸ä¾èµ–æŸè¡¥ä¸â€å°±å¥½äº†ã€‚ + +å¦‚æžœä½ ä¸èƒ½å°†è¡¥ä¸æµ“缩æˆæ›´å°‘的文件,那么æ¯æ¬¡å¤§çº¦å‘é€å‡º15个,然åŽç‰å¾…审查 +和整åˆã€‚ + +4)选择 e-mail 的收件人 + +看一é MAINTAINERS 文件和æºä»£ç ï¼Œçœ‹çœ‹ä½ æ‰€çš„æ”¹åŠ¨æ‰€åœ¨çš„å†…æ ¸å系统有没有指 +定的维护者。如果有,给他们å‘e-mail。 + +如果没有找到维护者,或者维护者没有åé¦ˆï¼Œå°†ä½ çš„è¡¥ä¸å‘é€åˆ°å†…æ ¸å¼€å‘者主邮 +件列表 linux-kernel@vger.kernel.orgã€‚å¤§éƒ¨åˆ†çš„å†…æ ¸å¼€å‘者都跟踪这个邮件列 +表,å¯ä»¥è¯„ä»·ä½ çš„æ”¹åŠ¨ã€‚ + +æ¯æ¬¡ä¸è¦å‘é€è¶…过15个补ä¸åˆ° vger 邮件列表ï¼ï¼ï¼ + +Linus Torvalds 是决定改动能å¦è¿›å…¥ Linux å†…æ ¸çš„æœ€ç»ˆè£å†³è€…。他的 e-mail +地å€æ˜¯ <torvalds@linux-foundation.org> 。他收到的 e-mail 很多,所以一般 +çš„è¯´ï¼Œæœ€å¥½åˆ«ç»™ä»–å‘ e-mail。 + +那些修æ£bug,“显而易è§â€çš„修改或者是类似的åªéœ€è¦å¾ˆå°‘讨论的补ä¸å¯ä»¥ç›´æŽ¥ +å‘é€æˆ–者CCç»™Linus。那些需è¦è®¨è®ºæˆ–者没有很清楚的好处的补ä¸ï¼Œä¸€èˆ¬å…ˆå‘é€åˆ° +linux-kernel邮件列表。åªæœ‰å½“è¡¥ä¸è¢«è®¨è®ºå¾—å·®ä¸å¤šäº†ï¼Œæ‰æ交给Linus。 + +5)选择CC( e-mail 抄é€)列表 + +除éžä½ 有ç†ç”±ä¸è¿™æ ·åšï¼Œå¦åˆ™CC linux-kernel@vger.kernel.org。 + +除了 Linus ä¹‹å¤–ï¼Œå…¶ä»–å†…æ ¸å¼€å‘者也需è¦æ³¨æ„åˆ°ä½ çš„æ”¹åŠ¨ï¼Œè¿™æ ·ä»–ä»¬æ‰èƒ½è¯„è®ºä½ +的改动并æ供代ç 审查和建议。linux-kernel 是 Linux å†…æ ¸å¼€å‘者主邮件列表 +。其它的邮件列表为特定的å系统æä¾›æœåŠ¡ï¼Œæ¯”如 USB,framebuffer 设备,虚 +拟文件系统,SCSI å系统,ç‰ç‰ã€‚查看 MAINTAINERS 文件æ¥èŽ·å¾—å’Œä½ çš„æ”¹åŠ¨æœ‰ +关的邮件列表。 + +Majordomo lists of VGER.KERNEL.ORG at: + <http://vger.kernel.org/vger-lists.html> + +如果改动影å“äº†ç”¨æˆ·ç©ºé—´å’Œå†…æ ¸ä¹‹é—´çš„æŽ¥å£ï¼Œè¯·ç»™ MAN-PAGES 的维护者(列在 +MAITAINERS 文件里的)å‘é€ä¸€ä¸ªæ‰‹å†Œé¡µï¼ˆman-pages)补ä¸ï¼Œæˆ–者至少通知一下改 +å˜ï¼Œè®©ä¸€äº›ä¿¡æ¯æœ‰é€”径进入手册页。 + +å³ä½¿åœ¨ç¬¬å››æ¥çš„时候,维护者没有作出回应,也è¦ç¡®è®¤åœ¨ä¿®æ”¹ä»–们的代ç 的时候 +,一直将维护者拷è´åˆ°CC列表ä¸ã€‚ + +对于å°çš„è¡¥ä¸ï¼Œä½ 也许会CC到 Adrian Bunk 管ç†çš„æœé›†ç碎补ä¸çš„邮件列表 +(Trivial Patch Monkey)trivial@kernel.org,那里专门收集ç碎的补ä¸ã€‚下é¢è¿™æ · +çš„è¡¥ä¸ä¼šè¢«çœ‹ä½œâ€œç碎的â€è¡¥ä¸ï¼š + 文档的拼写修æ£ã€‚ + ä¿®æ£ä¼šå½±å“到 grep(1) 的拼写。 + è¦å‘Šä¿¡æ¯ä¿®æ£(频ç¹çš„打å°æ— 用的è¦å‘Šæ˜¯ä¸å¥½çš„。) + 编译错误修æ£ï¼ˆä»£ç 逻辑的确是对的,åªæ˜¯ç¼–译有问题。) + è¿è¡Œæ—¶ä¿®æ£ï¼ˆåªè¦çœŸçš„ä¿®æ£äº†é”™è¯¯ã€‚) + 移除使用了被废弃的函数/å®çš„代ç (例如 check_region。) + è”系方å¼å’Œæ–‡æ¡£ä¿®æ£ã€‚ + 用å¯ç§»æ¤çš„代ç 替æ¢ä¸å¯ç§»æ¤çš„代ç (å³ä½¿åœ¨ä½“系结构相关的代ç ä¸ï¼Œæ—¢ç„¶æœ‰ + 人拷è´ï¼Œåªè¦å®ƒæ˜¯ç碎的) + 任何文件的作者/维护者对该文件的改动(例如 patch monkey 在é‡ä¼ 模å¼ä¸‹ï¼‰ + +URL: <http://www.kernel.org/pub/linux/kernel/people/bunk/trivial/> + +(译注,关于“ç碎补ä¸â€çš„ä¸€äº›è¯´æ˜Žï¼šå› ä¸ºåŽŸæ–‡çš„è¿™ä¸€éƒ¨åˆ†å†™å¾—æ¯”è¾ƒç®€å•ï¼Œæ‰€ä»¥ä¸å¾—ä¸ +è¿ä¾‹å†™ä¸€ä¸‹è¯‘注。"trivial"这个英文å•è¯çš„本æ„是“ç碎的,ä¸é‡è¦çš„。â€ä½†æ˜¯åœ¨è¿™é‡Œ +有ç¨å¾®æœ‰ä¸€äº›å˜åŒ–,例如对一些明显的NULL指针的修æ£ï¼Œå±žäºŽè¿è¡Œæ—¶ä¿®æ£ï¼Œä¼šè¢«å½’ç±» +到ç碎补ä¸é‡Œã€‚虽然NULL指针的修æ£å¾ˆé‡è¦ï¼Œä½†æ˜¯è¿™æ ·çš„ä¿®æ£å¾€å¾€å¾ˆå°è€Œä¸”很容易得到 +检验,所以也被归入ç碎补ä¸ã€‚ç碎补ä¸æ›´ç²¾ç¡®çš„归类应该是 +“simple, localized & easy to verifyâ€ï¼Œä¹Ÿå°±æ˜¯è¯´ç®€å•çš„,局部的和易于检验的。 +trivial@kernel.orgé‚®ä»¶åˆ—è¡¨çš„ç›®çš„æ˜¯é’ˆå¯¹è¿™æ ·çš„è¡¥ä¸ï¼Œä¸ºæ交者æ供一个ä¸å¿ƒï¼Œæ¥ +é™ä½Žæ交的门槛。) + +6)没有 MIME ç¼–ç ,没有链接,没有压缩,没有附件,åªæœ‰çº¯æ–‡æœ¬ã€‚ + +Linus å’Œå…¶ä»–çš„å†…æ ¸å¼€å‘者需è¦é˜…è¯»å’Œè¯„è®ºä½ æäº¤çš„æ”¹åŠ¨ã€‚å¯¹äºŽå†…æ ¸å¼€å‘者æ¥è¯´ +,å¯ä»¥â€œå¼•ç”¨â€ä½ 的改动很é‡è¦ï¼Œä½¿ç”¨ä¸€èˆ¬çš„ e-mail 工具,他们就å¯ä»¥åœ¨ä½ çš„ +代ç 的任何ä½ç½®æ·»åŠ 评论。 + +å› ä¸ºè¿™ä¸ªåŽŸå› ï¼Œæ‰€æœ‰çš„æ交的补ä¸éƒ½æ˜¯ e-mail ä¸â€œå†…嵌â€çš„。 +è¦å‘Šï¼šå¦‚æžœä½ ä½¿ç”¨å‰ªåˆ‡-ç²˜è´´ä½ çš„è¡¥ä¸ï¼Œå°å¿ƒä½ 的编辑器的自动æ¢è¡ŒåŠŸèƒ½ç ´åä½ çš„ +è¡¥ä¸ã€‚ + +ä¸è¦å°†è¡¥ä¸ä½œä¸º MIME ç¼–ç 的附件,ä¸ç®¡æ˜¯å¦åŽ‹ç¼©ã€‚很多æµè¡Œçš„ e-mail è½¯ä»¶ä¸ +是任何时候都将 MIME ç¼–ç 的附件当作纯文本å‘é€çš„ï¼Œè¿™ä¼šä½¿å¾—åˆ«äººæ— æ³•åœ¨ä½ çš„ +代ç ä¸åŠ 评论。å¦å¤–,MIME ç¼–ç 的附件会让 Linus 多花一点时间æ¥å¤„ç†ï¼Œè¿™å°± +é™ä½Žäº†ä½ 的改动被接å—çš„å¯èƒ½æ€§ã€‚ + +è¦å‘Šï¼šä¸€äº›é‚®ä»¶è½¯ä»¶ï¼Œæ¯”如 Mozilla ä¼šå°†ä½ çš„ä¿¡æ¯ä»¥å¦‚ä¸‹æ ¼å¼å‘é€ï¼š +---- 邮件头 ---- +Content-Type: text/plain; charset=us-ascii; format=flowed +---- 邮件头 ---- +问题在于 “format=flowed†会让接收端的æŸäº›é‚®ä»¶è½¯ä»¶å°†é‚®ä»¶ä¸çš„åˆ¶è¡¨ç¬¦æ›¿æ¢ +æˆç©ºæ ¼ä»¥åŠåšä¸€äº›ç±»ä¼¼çš„替æ¢ã€‚è¿™æ ·ï¼Œä½ å‘é€çš„时候看起æ¥æ²¡é—®é¢˜çš„è¡¥ä¸å°±è¢«ç ´ +å了。 + +è¦ä¿®æ£è¿™ä¸ªé—®é¢˜ï¼Œåªéœ€è¦å°†ä½ çš„ mozilla çš„ defaults/pref/mailnews.js 文件 +里的 +pref("mailnews.send_plaintext_flowed", false); // RFC 2646======= +ä¿®æ”¹æˆ +pref("mailnews.display.disable_format_flowed_support", true); +å°±å¯ä»¥äº†ã€‚ + +7) e-mail çš„å¤§å° + +ç»™ Linus å‘é€è¡¥ä¸çš„时候,永远按照第6å°èŠ‚说的åšã€‚ + +大的改动对邮件列表ä¸åˆé€‚,对æŸäº›ç»´æŠ¤è€…也ä¸åˆé€‚ã€‚å¦‚æžœä½ çš„è¡¥ä¸ï¼Œåœ¨ä¸åŽ‹ç¼© +的情况下,超过了40kBï¼Œé‚£ä¹ˆä½ æœ€å¥½å°†è¡¥ä¸æ”¾åœ¨ä¸€ä¸ªèƒ½é€šè¿‡ internet è®¿é—®çš„æœ +务器上,然åŽç”¨æŒ‡å‘ä½ çš„è¡¥ä¸çš„ URL 替代。 + +8) æŒ‡å‡ºä½ çš„å†…æ ¸ç‰ˆæœ¬ + +åœ¨æ ‡é¢˜å’Œåœ¨è¡¥ä¸çš„æè¿°ä¸ï¼ŒæŒ‡å‡ºè¡¥ä¸å¯¹åº”çš„å†…æ ¸çš„ç‰ˆæœ¬ï¼Œæ˜¯å¾ˆé‡è¦çš„。 + +如果补ä¸ä¸èƒ½å¹²å‡€çš„åœ¨æœ€æ–°ç‰ˆæœ¬çš„å†…æ ¸ä¸Šæ‰“ä¸Šï¼ŒLinus 是ä¸ä¼šæŽ¥å—它的。 + +9) ä¸è¦æ°”é¦ï¼Œç»§ç»æ交。 + +å½“ä½ æ交了改动以åŽï¼Œè€å¿ƒåœ°ç‰å¾…。如果 Linus å–œæ¬¢ä½ çš„æ”¹åŠ¨å¹¶ä¸”åŒæ„它,那么 +å®ƒå°†åœ¨ä¸‹ä¸€ä¸ªå†…æ ¸å‘布版本ä¸å‡ºçŽ°ã€‚ + +ç„¶è€Œï¼Œå¦‚æžœä½ çš„æ”¹åŠ¨æ²¡æœ‰å‡ºçŽ°åœ¨ä¸‹ä¸€ä¸ªç‰ˆæœ¬çš„å†…æ ¸ä¸ï¼Œå¯èƒ½æœ‰è‹¥å¹²åŽŸå› 。å‡å°‘é‚£ +äº›åŽŸå› ï¼Œä¿®æ£é”™è¯¯ï¼Œé‡æ–°æ交更新åŽçš„æ”¹åŠ¨ï¼Œæ˜¯ä½ è‡ªå·±çš„å·¥ä½œã€‚ + +Linusä¸ç»™å‡ºä»»ä½•è¯„论就“丢弃â€ä½ çš„è¡¥ä¸æ˜¯å¸¸è§çš„事情。在系统ä¸è¿™æ ·çš„事情很 +平常。如果他没有接å—ä½ çš„è¡¥ä¸ï¼Œä¹Ÿè®¸æ˜¯ç”±äºŽä»¥ä¸‹åŽŸæœ¬ï¼š +* ä½ çš„è¡¥ä¸ä¸èƒ½åœ¨æœ€æ–°ç‰ˆæœ¬çš„å†…æ ¸ä¸Šå¹²å‡€çš„æ‰“ä¸Šã€‚ +* ä½ çš„è¡¥ä¸åœ¨ linux-kernel 邮件列表ä¸æ²¡æœ‰å¾—到充分的讨论。 +* é£Žæ ¼é—®é¢˜ï¼ˆå‚照第2å°èŠ‚) +* é‚®ä»¶æ ¼å¼é—®é¢˜ï¼ˆé‡è¯»æœ¬èŠ‚) +* ä½ çš„æ”¹åŠ¨æœ‰æŠ€æœ¯é—®é¢˜ã€‚ +* 他收到了æˆå¨çš„ e-mailï¼Œè€Œä½ çš„åœ¨æ··ä¹±ä¸ä¸¢å¤±äº†ã€‚ +* ä½ è®©äººä¸ºéš¾ã€‚ + +有疑问的时候,在 linux-kernel 邮件列表上请求评论。 + +10) åœ¨æ ‡é¢˜ä¸ŠåŠ ä¸Š PATCH çš„å—æ · + +Linus å’Œ linux-kernel 邮件列表的 e-mail æµé‡éƒ½å¾ˆé«˜ï¼Œä¸€ä¸ªé€šå¸¸çš„çº¦å®šæ˜¯æ ‡ +题行以 [PATCH] å¼€å¤´ã€‚è¿™æ ·å¯ä»¥è®© Linus å’Œå…¶ä»–å†…æ ¸å¼€å‘人员å¯ä»¥ä»Ž e-mail +的讨论ä¸å¾ˆè½»æ˜“的将补ä¸åˆ†è¾¨å‡ºæ¥ã€‚ + +11ï¼‰ä¸ºä½ çš„å·¥ä½œç¾å + +ä¸ºäº†åŠ å¼ºå¯¹è°åšäº†ä½•äº‹çš„追踪,尤其是对那些é€è¿‡å¥½å‡ 层的维护者的补ä¸ï¼Œæˆ‘们 +建议在å‘é€å‡ºåŽ»çš„è¡¥ä¸ä¸ŠåŠ 一个 “sign-off†的过程。 + +"sign-off" 是在补ä¸çš„注释的最åŽçš„简å•çš„一行文å—,认è¯ä½ 编写了它或者其他 +人有æƒåŠ›å°†å®ƒä½œä¸ºå¼€æ”¾æºä»£ç çš„è¡¥ä¸ä¼ 递。规则很简å•ï¼šå¦‚æžœä½ èƒ½è®¤è¯å¦‚ä¸‹ä¿¡æ¯ +: + å¼€å‘者æ¥æºè¯ä¹¦ 1.1 + 对于本项目的贡献,我认è¯å¦‚下信æ¯ï¼š + (a)这些贡献是完全或者部分的由我创建,我有æƒåˆ©ä»¥æ–‡ä»¶ä¸æŒ‡å‡º + 的开放æºä»£ç 许å¯è¯æ交它;或者 + (b)这些贡献基于以å‰çš„工作,æ®æˆ‘所知,这些以å‰çš„工作å—æ°å½“的开放 + æºä»£ç 许å¯è¯ä¿æŠ¤ï¼Œè€Œä¸”ï¼Œæ ¹æ®è®¸å¯è¯ï¼Œæˆ‘有æƒæ交修改åŽçš„贡献, + æ— è®ºæ˜¯å®Œå…¨è¿˜æ˜¯éƒ¨åˆ†ç”±æˆ‘åˆ›é€ ï¼Œè¿™äº›è´¡çŒ®éƒ½ä½¿ç”¨åŒä¸€ä¸ªå¼€æ”¾æºä»£ç 许å¯è¯ + (除éžæˆ‘被å…许用其它的许å¯è¯ï¼‰ï¼Œæ£å¦‚文件ä¸æŒ‡å‡ºçš„;或者 + (c)这些贡献由认è¯ï¼ˆa),(b)或者(c)的人直接æ供给我,而 + 且我没有修改它。 + (d)我ç†è§£å¹¶åŒæ„这个项目和贡献是公开的,贡献的记录(包括我 + 一起æ交的个人记录,包括 sign-off )被永久维护并且å¯ä»¥å’Œè¿™ä¸ªé¡¹ç›® + 或者开放æºä»£ç 的许å¯è¯åŒæ¥åœ°å†å‘行。 + é‚£ä¹ˆåŠ å…¥è¿™æ ·ä¸€è¡Œï¼š + Signed-off-by: Random J Developer <random@developer.example.org> + +ä½¿ç”¨ä½ çš„çœŸå(抱æ‰ï¼Œä¸èƒ½ä½¿ç”¨å‡å或者匿å。) + +有人在最åŽåŠ ä¸Šæ ‡ç¾ã€‚çŽ°åœ¨è¿™äº›ä¸œè¥¿ä¼šè¢«å¿½ç•¥ï¼Œä½†æ˜¯ä½ å¯ä»¥è¿™æ ·åšï¼Œæ¥æ ‡è®°å…¬å¸ +内部的过程,或者åªæ˜¯æŒ‡å‡ºå…³äºŽ sign-off 的一些特殊细节。 + +12ï¼‰æ ‡å‡†è¡¥ä¸æ ¼å¼ + +æ ‡å‡†çš„è¡¥ä¸ï¼Œæ ‡é¢˜è¡Œæ˜¯ï¼š + Subject: [PATCH 001/123] å系统:一å¥è¯æ¦‚è¿° + +æ ‡å‡†è¡¥ä¸çš„信体å˜åœ¨å¦‚下部分: + + - 一个 "from" 行指出补ä¸ä½œè€…。 + + - 一个空行 + + - 说明的主体,这些说明文å—会被拷è´åˆ°æ述该补ä¸çš„永久改动记录里。 + + - 一个由"---"æž„æˆçš„æ ‡è®°è¡Œ + + - ä¸åˆé€‚放到改动记录里的é¢å¤–的注解。 + + - è¡¥ä¸æœ¬èº«ï¼ˆdiff 输出) + +æ ‡é¢˜è¡Œçš„æ ¼å¼ï¼Œä½¿å¾—å¯¹æ ‡é¢˜è¡ŒæŒ‰å—æ¯åºæŽ’åºéžå¸¸çš„容易 - 很多 e-mail 客户端都 +å¯ä»¥æ”¯æŒ - å› ä¸ºåºåˆ—å·æ˜¯ç”¨é›¶å¡«å……的,所以按数å—排åºå’ŒæŒ‰å—æ¯æŽ’åºæ˜¯ä¸€æ ·çš„。 + +e-mail æ ‡é¢˜ä¸çš„“å系统â€æ ‡è¯†å“ªä¸ªå†…æ ¸å系统将被打补ä¸ã€‚ + +e-mail æ ‡é¢˜ä¸çš„“一å¥è¯æ¦‚è¿°â€æ‰¼è¦çš„æè¿° e-mail ä¸çš„è¡¥ä¸ã€‚“一å¥è¯æ¦‚述†+ä¸åº”该是一个文件å。对于一个补ä¸ç³»åˆ—(“补ä¸ç³»åˆ—â€æŒ‡ä¸€ç³»åˆ—的多个相关补 +ä¸ï¼‰ï¼Œä¸è¦å¯¹æ¯ä¸ªè¡¥ä¸éƒ½ä½¿ç”¨åŒæ ·çš„“一å¥è¯æ¦‚è¿°â€ã€‚ + +è®°ä½ e-mail 的“一å¥è¯æ¦‚è¿°â€ä¼šæˆä¸ºè¯¥è¡¥ä¸çš„å…¨å±€å”¯ä¸€æ ‡è¯†ã€‚å®ƒä¼šè”“å»¶åˆ° git +的改动记录里。然åŽâ€œä¸€å¥è¯æ¦‚è¿°â€ä¼šè¢«ç”¨åœ¨å¼€å‘者的讨论里,用æ¥æŒ‡ä»£è¿™ä¸ªè¡¥ +ä¸ã€‚用户将希望通过 google æ¥æœç´¢"一å¥è¯æ¦‚è¿°"æ¥æ‰¾åˆ°é‚£äº›è®¨è®ºè¿™ä¸ªè¡¥ä¸çš„æ–‡ +ç« ã€‚ + +ä¸€äº›æ ‡é¢˜çš„ä¾‹å: + + Subject: [patch 2/5] ext2: improve scalability of bitmap searching + Subject: [PATCHv2 001/207] x86: fix eflags tracking + +"from" 行是信体里的最上é¢ä¸€è¡Œï¼Œå…·æœ‰å¦‚ä¸‹æ ¼å¼ï¼š + From: Original Author <author@example.com> + +"from" 行指明在永久改动日志里,è°ä¼šè¢«ç¡®è®¤ä¸ºä½œè€…。如果没有 "from" 行,那 +么邮件头里的 "From: " 行会被用æ¥å†³å®šæ”¹åŠ¨æ—¥å¿—ä¸çš„作者。 + +说明的主题将会被æ交到永久的æºä»£ç æ”¹åŠ¨æ—¥å¿—é‡Œï¼Œå› æ¤å¯¹é‚£äº›æ—©å·²ç»ä¸è®°å¾—å’Œ +这个补ä¸ç›¸å…³çš„讨论细节的有能力的读者æ¥è¯´ï¼Œæ˜¯æœ‰æ„义的。 + +"---" æ ‡è®°è¡Œå¯¹äºŽè¡¥ä¸å¤„ç†å·¥å…·è¦æ‰¾åˆ°å“ªé‡Œæ˜¯æ”¹åŠ¨æ—¥å¿—ä¿¡æ¯çš„结æŸï¼Œæ˜¯ä¸å¯ç¼ºå°‘ +的。 + +对于 "---" æ ‡è®°ä¹‹åŽçš„é¢å¤–注解,一个好的用途就是用æ¥å†™ diffstat,用æ¥æ˜¾ +示修改了什么文件和æ¯ä¸ªæ–‡ä»¶éƒ½å¢žåŠ å’Œåˆ é™¤äº†å¤šå°‘è¡Œã€‚diffstat 对于比较大的补 +ä¸ç‰¹åˆ«æœ‰ç”¨ã€‚其余那些åªæ˜¯å’Œæ—¶åˆ»æˆ–者开å‘者相关的注解,ä¸åˆé€‚放到永久的改 +动日志里的,也应该放这里。 +使用 diffstat的选项 "-p 1 -w 70" è¿™æ ·æ–‡ä»¶åå°±ä¼šä»Žå†…æ ¸æºä»£ç æ ‘çš„ç›®å½•å¼€å§‹ +,ä¸ä¼šå 用太宽的空间(很容易适åˆ80列的宽度,也许会有一些缩进。) + +在åŽé¢çš„å‚考资料ä¸èƒ½çœ‹åˆ°é€‚当的补ä¸æ ¼å¼çš„更多细节。 + +------------------------------- +第二节 æç¤ºï¼Œå»ºè®®å’Œè¯€çª +------------------------------- + +本节包å«å¾ˆå¤šå’Œæäº¤åˆ°å†…æ ¸çš„ä»£ç 有关的通常的"规则"。事情永远有例外...但是 +ä½ å¿…é¡»çœŸçš„æœ‰å¥½çš„ç†ç”±è¿™æ ·åšã€‚ä½ å¯ä»¥æŠŠæœ¬èŠ‚å«åšLinus的计算机科å¦å…¥é—¨è¯¾ã€‚ + +1) 读 Document/CodingStyle + +Nuff è¯´è¿‡ï¼Œå¦‚æžœä½ çš„ä»£ç 和这个å离太多,那么它有å¯èƒ½ä¼šè¢«æ‹’ç»ï¼Œæ²¡æœ‰æ›´å¤šçš„ +审查,没有更多的评价。 + +2) #ifdef 是丑陋的 +æ··æ‚了 ifdef 的代ç éš¾ä»¥é˜…è¯»å’Œç»´æŠ¤ã€‚åˆ«è¿™æ ·åšã€‚ä½œä¸ºæ›¿ä»£ï¼Œå°†ä½ çš„ ifdef 放 +在头文件里,有æ¡ä»¶åœ°å®šä¹‰ "static inline" 函数,或者å®ï¼Œåœ¨ä»£ç 里用这些东 +西。让编译器把那些"空æ“作"优化掉。 + +一个简å•çš„例å,ä¸å¥½çš„代ç : + + dev = alloc_etherdev (sizeof(struct funky_private)); + if (!dev) + return -ENODEV; + #ifdef CONFIG_NET_FUNKINESS + init_funky_net(dev); + #endif + +清ç†åŽçš„例å: + +(头文件里) + #ifndef CONFIG_NET_FUNKINESS + static inline void init_funky_net (struct net_device *d) {} + #endif + +(代ç 文件里) + dev = alloc_etherdev (sizeof(struct funky_private)); + if (!dev) + return -ENODEV; + init_funky_net(dev); + +3) 'static inline' 比å®å¥½ + +Static inline 函数相比å®æ¥è¯´ï¼Œæ˜¯å¥½å¾—多的选择。Static inline 函数æ供了 +类型安全,没有长度é™åˆ¶ï¼Œæ²¡æœ‰æ ¼å¼é™åˆ¶ï¼Œåœ¨ gcc 下开销和å®ä¸€æ ·å°ã€‚ + +å®åªåœ¨ static inline 函数ä¸æ˜¯æœ€ä¼˜çš„时候[在 fast paths 里有很少的独立的 +案例],或者ä¸å¯èƒ½ç”¨ static inline 函数的时候[例如å—符串分é…]。 +应该用 'static inline' 而ä¸æ˜¯ 'static __inline__', 'extern inline' å’Œ +'extern __inline__' 。 + +4) ä¸è¦è¿‡åº¦è®¾è®¡ + +ä¸è¦è¯•å›¾é¢„计模糊的未æ¥äº‹æƒ…,这些事情也许有用也许没有用:"让事情尽å¯èƒ½çš„ +简å•ï¼Œè€Œä¸æ˜¯æ›´ç®€å•"。 + +---------------- +第三节 å‚考文献 +---------------- + +Andrew Morton, "The perfect patch" (tpp). + <http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt> + +Jeff Garzik, "Linux kernel patch submission format". + <http://linux.yyz.us/patch-format.html> + +Greg Kroah-Hartman, "How to piss off a kernel subsystem maintainer". + <http://www.kroah.com/log/2005/03/31/> + <http://www.kroah.com/log/2005/07/08/> + <http://www.kroah.com/log/2005/10/19/> + <http://www.kroah.com/log/2006/01/11/> + +NO!!!! No more huge patch bombs to linux-kernel@vger.kernel.org people! + <http://marc.theaimsgroup.com/?l=linux-kernel&m=112112749912944&w=2> + +Kernel Documentation/CodingStyle: + <http://sosdg.org/~coywolf/lxr/source/Documentation/CodingStyle> + +Linus Torvalds's mail on the canonical patch format: + <http://lkml.org/lkml/2005/4/7/183> +-- diff --git a/Documentation/zh_CN/oops-tracing.txt b/Documentation/zh_CN/oops-tracing.txt new file mode 100644 index 0000000000000000000000000000000000000000..9312608ffb8d13a58d7e8a0255ecbe5d6dba6cd1 --- /dev/null +++ b/Documentation/zh_CN/oops-tracing.txt @@ -0,0 +1,212 @@ +Chinese translated version of Documentation/oops-tracing.txt + +If you have any comment or update to the content, please contact the +original document maintainer directly. However, if you have a problem +communicating in English you can also ask the Chinese maintainer for +help. Contact the Chinese maintainer if this translation is outdated +or if there is a problem with the translation. + +Chinese maintainer: Dave Young <hidave.darkstar@gmail.com> +--------------------------------------------------------------------- +Documentation/oops-tracing.txt çš„ä¸æ–‡ç¿»è¯‘ + +如果想评论或更新本文的内容,请直接è”ç³»åŽŸæ–‡æ¡£çš„ç»´æŠ¤è€…ã€‚å¦‚æžœä½ ä½¿ç”¨è‹±æ–‡ +交æµæœ‰å›°éš¾çš„è¯ï¼Œä¹Ÿå¯ä»¥å‘ä¸æ–‡ç‰ˆç»´æŠ¤è€…求助。如果本翻译更新ä¸åŠæ—¶æˆ–者翻 +译å˜åœ¨é—®é¢˜ï¼Œè¯·è”ç³»ä¸æ–‡ç‰ˆç»´æŠ¤è€…。 + +ä¸æ–‡ç‰ˆç»´æŠ¤è€…: æ¨ç‘ž Dave Young <hidave.darkstar@gmail.com> +ä¸æ–‡ç‰ˆç¿»è¯‘者: æ¨ç‘ž Dave Young <hidave.darkstar@gmail.com> +ä¸æ–‡ç‰ˆæ ¡è¯‘者: æŽé˜³ Li Yang <leo@zh-kernel.org> + çŽ‹èª Wang Cong <xiyou.wangcong@gmail.com> + +以下为æ£æ–‡ +--------------------------------------------------------------------- + +注æ„: ksymoops 在2.6ä¸æ˜¯æ²¡æœ‰ç”¨çš„。 è¯·ä»¥åŽŸæœ‰æ ¼å¼ä½¿ç”¨Oops(æ¥è‡ªdmesg,ç‰ç‰)。 +å¿½ç•¥ä»»ä½•è¿™æ ·é‚£æ ·å…³äºŽâ€œè§£ç Oopsâ€æˆ–者“通过ksymoopsè¿è¡Œâ€çš„文档。 å¦‚æžœä½ è´´å‡ºè¿è¡Œè¿‡ +ksymoopsçš„æ¥è‡ª2.6çš„Oops,人们åªä¼šè®©ä½ é‡è´´ä¸€æ¬¡ã€‚ + +快速总结 +------------- + +å‘现Oops并å‘é€ç»™çœ‹ä¼¼ç›¸å…³çš„å†…æ ¸é¢†åŸŸçš„ç»´æŠ¤è€…ã€‚åˆ«å¤ªæ‹…å¿ƒå¯¹ä¸ä¸Šå·ã€‚å¦‚æžœä½ ä¸ç¡®å®šå°±å‘ç»™ +å’Œä½ æ‰€åšçš„事情相关的代ç 的负责人。 如果å¯é‡çŽ°è¯•ç€æè¿°æ€Žæ ·é‡æž„。 那甚至比oops更有 +价值。 + +å¦‚æžœä½ å¯¹äºŽå‘é€ç»™è°ä¸€æ— 所知, å‘ç»™linux-kernel@vger.kernel.orgã€‚æ„Ÿè°¢ä½ å¸®åŠ©Linux +å°½å¯èƒ½åœ°ç¨³å®šã€‚ + +Oops在哪里? +---------------------- + +通常Oops文本由klogdä»Žå†…æ ¸ç¼“å†²åŒºé‡Œè¯»å–å¹¶ä¼ ç»™syslogd,由syslogd写到syslog文件ä¸ï¼Œ +典型地是/var/log/messages(ä¾èµ–于/etc/syslog.conf)。有时klogd崩溃了,è¿™ç§æƒ…å†µä¸‹ä½ +能够è¿è¡Œdmesg > fileæ¥ä»Žå†…æ ¸ç¼“å†²åŒºä¸è¯»å–æ•°æ®å¹¶ä¿å˜ä¸‹æ¥ã€‚ å¦åˆ™ä½ å¯ä»¥ +cat /proc/kmsg > file, ç„¶è€Œä½ å¿…é¡»ä»‹å…¥ä¸æ¢ä¼ 输, kmsg是一个“永ä¸ç»“æŸçš„文件â€ã€‚如 +果机器崩溃ååˆ°ä½ ä¸èƒ½è¾“入命令或者ç£ç›˜ä¸å¯ç”¨é‚£ä¹ˆä½ 有三ç§é€‰æ‹©:- + +(1) 手抄å±å¹•ä¸Šçš„文本待机器é‡å¯åŽå†è¾“入计算机。 麻烦但如果没有针对崩溃的准备, +这是仅有的选择。 å¦å¤–ï¼Œä½ å¯ä»¥ç”¨æ•°ç 相机把å±å¹•æ‹ä¸‹æ¥-ä¸å¤ªå¥½ï¼Œä½†æ¯”没有强。 如果信 +æ¯æ»šåŠ¨åˆ°äº†ç»ˆç«¯çš„上é¢ï¼Œä½ 会å‘现以高分辩率å¯åŠ¨ï¼ˆæ¯”如,vga=791ï¼‰ä¼šè®©ä½ è¯»åˆ°æ›´å¤šçš„æ–‡ +本。(注æ„:这需è¦vesafb,所以对‘早期’的oops没有帮助) + +(2)用串å£ç»ˆç«¯å¯åŠ¨ï¼ˆè¯·å‚看Documentation/serial-console.txt),è¿è¡Œä¸€ä¸ªnull +modem到å¦ä¸€å°æœºå™¨å¹¶ç”¨ä½ 喜欢的通讯工具获å–输出。Minicom工作地很好。 + +(3)使用Kdump(请å‚看Documentation/kdump/kdump.txt), +使用在Documentation/kdump/gdbmacros.txtä¸å®šä¹‰çš„dmesg gdbå®ï¼Œä»Žæ—§çš„内å˜ä¸æå–å†…æ ¸ +环形缓冲区。 + +å®Œæ•´ä¿¡æ¯ +---------------- + +注æ„:以下æ¥è‡ªäºŽLinus的邮件适用于2.4å†…æ ¸ã€‚ æˆ‘å› ä¸ºåŽ†å²åŽŸå› ä¿ç•™äº†å®ƒï¼Œå¹¶ä¸”å› ä¸ºå…¶ä¸ +一些信æ¯ä»ç„¶é€‚用。 特别注æ„的是,请忽略任何ksymoops的引用。 + +From: Linus Torvalds <torvalds@osdl.org> + +æ€Žæ ·è·Ÿè¸ªOops.. [原å‘到linux-kernel的一å°é‚®ä»¶] + +主è¦çš„çªé—¨æ˜¯æœ‰äº”年和这些烦人的oops消æ¯æ‰“交é“çš„ç»éªŒ;-) + +å®žé™…ä¸Šï¼Œä½ æœ‰åŠžæ³•ä½¿å®ƒæ›´ç®€å•ã€‚我有两个ä¸åŒçš„方法: + + gdb /usr/src/linux/vmlinux + gdb> disassemble <offending_function> + +那是å‘现问题的简å•åŠžæ³•ï¼Œè‡³å°‘如果bug报告åšçš„å¥½çš„æƒ…å†µä¸‹ï¼ˆè±¡è¿™ä¸ªä¸€æ ·-è¿è¡Œksymoops +得到oopså‘生的函数åŠå‡½æ•°å†…çš„å移)。 + +哦,如果报告å‘ç”Ÿçš„å†…æ ¸ä»¥ç›¸åŒçš„编译器和相似的é…置编译它会有帮助的。 + +å¦ä¸€ä»¶è¦åšçš„事是å汇编bug报告的“Codeâ€éƒ¨åˆ†ï¼šksymoops也会用æ£ç¡®çš„工具æ¥åšè¿™ä»¶äº‹ï¼Œ +ä½†å¦‚æžœæ²¡æœ‰é‚£äº›å·¥å…·ä½ å¯ä»¥å†™ä¸€ä¸ªå‚»ç¨‹åºï¼š + + char str[] = "\xXX\xXX\xXX..."; + main(){} + +并用gcc -g编译它然åŽæ‰§è¡Œâ€œdisassemble strâ€ï¼ˆXX部分是由Oops报告的值-ä½ å¯ä»¥ä»…剪切 +粘贴并用“\xâ€æ›¿æ¢ç©ºæ ¼-我就是这么åšçš„ï¼Œå› ä¸ºæˆ‘æ‡’å¾—å†™ç¨‹åºè‡ªåŠ¨åšè¿™ä¸€åˆ‡ï¼‰ã€‚ + +å¦å¤–ï¼Œä½ å¯ä»¥ç”¨scripts/decodecode这个shell脚本。它的使用方法是: +decodecode < oops.txt + +“Codeâ€ä¹‹åŽçš„åå…进制å—节å¯èƒ½ï¼ˆåœ¨æŸäº›æž¶æž„上)有一些当å‰æŒ‡ä»¤ä¹‹å‰çš„指令å—èŠ‚ä»¥åŠ +当å‰å’Œä¹‹åŽçš„指令å—节 + +Code: f9 0f 8d f9 00 00 00 8d 42 0c e8 dd 26 11 c7 a1 60 ea 2b f9 8b 50 08 a1 +64 ea 2b f9 8d 34 82 8b 1e 85 db 74 6d 8b 15 60 ea 2b f9 <8b> 43 04 39 42 54 +7e 04 40 89 42 54 8b 43 04 3b 05 00 f6 52 c0 + +最åŽï¼Œå¦‚æžœä½ æƒ³çŸ¥é“代ç æ¥è‡ªå“ªé‡Œï¼Œä½ å¯ä»¥ï¼š + + cd /usr/src/linux + make fs/buffer.s # 或任何产生BUG的文件 + +然åŽä½ 会比gdbå汇编更清楚的知é“å‘生了什么。 + +çŽ°åœ¨ï¼Œé—®é¢˜æ˜¯æŠŠä½ æ‰€æ‹¥æœ‰çš„æ‰€æœ‰æ•°æ®ç»“åˆèµ·æ¥ï¼šCæºç ï¼ˆå…³äºŽå®ƒåº”è¯¥æ€Žæ ·çš„ä¸€èˆ¬çŸ¥è¯†ï¼‰ï¼Œ +汇编代ç åŠå…¶å汇编得到的代ç (å¦å¤–还有从“oopsâ€æ¶ˆæ¯å¾—到的寄å˜å™¨çŠ¶æ€-对了解æ¯åçš„ +æŒ‡é’ˆæœ‰ç”¨ï¼Œè€Œä¸”å½“ä½ æœ‰äº†æ±‡ç¼–ä»£ç ä½ ä¹Ÿèƒ½æ‹¿å…¶å®ƒçš„å¯„å˜å™¨å’Œä»»ä½•å®ƒä»¬å¯¹åº”çš„C表达å¼åšåŒ¹é… +)。 + +å®žé™…ä¸Šï¼Œä½ ä»…éœ€çœ‹çœ‹å“ªé‡Œä¸åŒ¹é…(这个例å是“Codeâ€å汇编和编译器生æˆçš„代ç ä¸åŒ¹é…)。 +然åŽä½ é¡»è¦æ‰¾å‡ºä¸ºä»€ä¹ˆä¸åŒ¹é…。通常很简å•-ä½ çœ‹åˆ°ä»£ç 使用了空指针然åŽä½ 看代ç æƒ³çŸ¥é“ +空指针是怎么出现的,还有检查它是å¦åˆæ³•.. + +现在,如果明白这是一项耗时的工作而且需è¦ä¸€ä¸ç‚¹å„¿çš„专心,没错。这就是我为什么大多 +åªæ˜¯å¿½ç•¥é‚£äº›æ²¡æœ‰ç¬¦å·è¡¨ä¿¡æ¯çš„å´©æºƒæŠ¥å‘Šçš„åŽŸå› ï¼šç®€å•çš„说太难查找了(我有一些 +程åºç”¨äºŽåœ¨å†…æ ¸ä»£ç 段ä¸æœç´¢ç‰¹å®šçš„模å¼ï¼Œè€Œä¸”有时我也已ç»èƒ½æ‰¾å‡ºé‚£äº›å´©æºƒçš„地方,但是 +仅仅是找出æ£ç¡®çš„åºåˆ—也确实需è¦ç›¸å½“æ‰Žå®žçš„å†…æ ¸çŸ¥è¯†ï¼‰ + +_有时_会å‘生这ç§æƒ…况,我仅看到崩溃ä¸çš„å汇编代ç åºåˆ—, 然åŽæˆ‘马上就明白问题出在 +哪里。这时我æ‰æ„识到自己干这个工作已ç»å¤ªé•¿æ—¶é—´äº†;-) + + Linus + + +--------------------------------------------------------------------------- +关于Oops跟踪的注解: + +为了帮助Linuså’Œå…¶å®ƒå†…æ ¸å¼€å‘者,klogd纳入了大é‡çš„支æŒæ¥å¤„ç†ä¿æŠ¤é”™è¯¯ã€‚为了拥有对 +地å€è§£æžçš„完整支æŒè‡³å°‘应该使用1.3-pl3çš„sysklogd包。 + +当ä¿æŠ¤é”™è¯¯å‘生时,klogdå®ˆæŠ¤è¿›ç¨‹è‡ªåŠ¨æŠŠå†…æ ¸æ—¥å¿—ä¿¡æ¯ä¸çš„é‡è¦åœ°å€ç¿»è¯‘æˆå®ƒä»¬ç›¸åº”的符 +å·ã€‚ + +klogd执行两ç§ç±»åž‹çš„地å€è§£æžã€‚首先是é™æ€ç¿»è¯‘其次是动æ€ç¿»è¯‘。é™æ€ç¿»è¯‘å’Œksymoops +ä¸€æ ·ä½¿ç”¨System.map文件。为了åšé™æ€ç¿»è¯‘klogd守护进程必须在åˆå§‹åŒ–时能找到system +map文件。关于klogdæ€Žæ ·æœç´¢map文件请å‚看klogd手册页。 + +动æ€åœ°å€ç¿»è¯‘åœ¨ä½¿ç”¨å†…æ ¸å¯è£…载模å—时很é‡è¦ã€‚ å› ä¸ºå†…æ ¸æ¨¡å—的内å˜æ˜¯ä»Žå†…æ ¸åŠ¨æ€å†…å˜æ± +里分é…的,所以ä¸ç®¡æ˜¯æ¨¡å—开始ä½ç½®è¿˜æ˜¯æ¨¡å—ä¸å‡½æ•°å’Œç¬¦å·çš„ä½ç½®éƒ½ä¸æ˜¯å›ºå®šçš„。 + +å†…æ ¸æ”¯æŒå…许程åºå†³å®šè£…载哪些模å—和它们在内å˜ä¸ä½ç½®çš„系统调用。使用这些系统调用 +klogd守护进程生æˆä¸€å¼ 符å·è¡¨ç”¨äºŽè°ƒè¯•å‘生在å¯è£…载模å—ä¸çš„ä¿æŠ¤é”™è¯¯ã€‚ + +至少klogd会æ供产生ä¿æŠ¤é”™è¯¯çš„模å—å。还å¯æœ‰é¢å¤–的符å·ä¿¡æ¯ä¾›å¯è£…载模å—å¼€å‘者选择 +以从模å—ä¸è¾“出符å·ä¿¡æ¯ã€‚ + +å› ä¸ºå†…æ ¸æ¨¡å—环境å¯èƒ½æ˜¯åŠ¨æ€çš„,所以必须有一ç§æœºåˆ¶å½“模å—环境å‘生改å˜æ—¶æ¥é€šçŸ¥klogd +守护进程。 有一些å¯ç”¨çš„命令行选项å…许klogdå‘当å‰æ‰§è¡Œä¸çš„守护进程å‘é€ä¿¡å·ï¼Œå‘ŠçŸ¥ç¬¦ +å·ä¿¡æ¯åº”该被刷新了。 更多信æ¯è¯·å‚看klogd手册页。 + +sysklogdå‘布时包å«ä¸€ä¸ªè¡¥ä¸ä¿®æ”¹äº†modules-2.0.0åŒ…ï¼Œæ— è®ºä½•æ—¶ä¸€ä¸ªæ¨¡å—装载或者å¸è½½éƒ½ +会自动å‘klogdå‘é€ä¿¡å·ã€‚打上这个补ä¸æ供了必è¦çš„对调试å‘ç”ŸäºŽå†…æ ¸å¯è£…载模å—çš„ä¿æŠ¤ +é”™è¯¯çš„æ— ç¼æ”¯æŒã€‚ + +以下是被klogd处ç†è¿‡çš„å‘生在å¯è£…载模å—ä¸çš„一个ä¿æŠ¤é”™è¯¯ä¾‹å: +--------------------------------------------------------------------------- +Aug 29 09:51:01 blizard kernel: Unable to handle kernel paging request at virtual address f15e97cc +Aug 29 09:51:01 blizard kernel: current->tss.cr3 = 0062d000, %cr3 = 0062d000 +Aug 29 09:51:01 blizard kernel: *pde = 00000000 +Aug 29 09:51:01 blizard kernel: Oops: 0002 +Aug 29 09:51:01 blizard kernel: CPU: 0 +Aug 29 09:51:01 blizard kernel: EIP: 0010:[oops:_oops+16/3868] +Aug 29 09:51:01 blizard kernel: EFLAGS: 00010212 +Aug 29 09:51:01 blizard kernel: eax: 315e97cc ebx: 003a6f80 ecx: 001be77b edx: 00237c0c +Aug 29 09:51:01 blizard kernel: esi: 00000000 edi: bffffdb3 ebp: 00589f90 esp: 00589f8c +Aug 29 09:51:01 blizard kernel: ds: 0018 es: 0018 fs: 002b gs: 002b ss: 0018 +Aug 29 09:51:01 blizard kernel: Process oops_test (pid: 3374, process nr: 21, stackpage=00589000) +Aug 29 09:51:01 blizard kernel: Stack: 315e97cc 00589f98 0100b0b4 bffffed4 0012e38e 00240c64 003a6f80 00000001 +Aug 29 09:51:01 blizard kernel: 00000000 00237810 bfffff00 0010a7fa 00000003 00000001 00000000 bfffff00 +Aug 29 09:51:01 blizard kernel: bffffdb3 bffffed4 ffffffda 0000002b 0007002b 0000002b 0000002b 00000036 +Aug 29 09:51:01 blizard kernel: Call Trace: [oops:_oops_ioctl+48/80] [_sys_ioctl+254/272] [_system_call+82/128] +Aug 29 09:51:01 blizard kernel: Code: c7 00 05 00 00 00 eb 08 90 90 90 90 90 90 90 90 89 ec 5d c3 +--------------------------------------------------------------------------- + +Dr. G.W. Wettstein Oncology Research Div. Computing Facility +Roger Maris Cancer Center INTERNET: greg@wind.rmcc.com +820 4th St. N. +Fargo, ND 58122 +Phone: 701-234-7556 + + +--------------------------------------------------------------------------- +å—æ±¡æŸ“çš„å†…æ ¸ + +一些oops报告在程åºè®°æ•°å™¨ä¹‹åŽåŒ…å«å—符串'Tainted: 'ã€‚è¿™è¡¨æ˜Žå†…æ ¸å·²ç»è¢«ä¸€äº›ä¸œè¥¿ç»™æ±¡ +染了。 该å—符串之åŽç´§è·Ÿç€ä¸€ç³»åˆ—çš„ä½ç½®æ•æ„Ÿçš„å—符,æ¯ä¸ªä»£è¡¨ä¸€ä¸ªç‰¹å®šçš„污染值。 + + 1:'G'如果所有装载的模å—都有GPL或相容的许å¯è¯ï¼Œ'P'如果装载了任何的专有模å—。 +没有模å—MODULE_LICENSE或者带有insmod认为是与GPLä¸ç›¸å®¹çš„çš„MODULE_LICENSE的模å—被 +认定是专有的。 + + 2:'F'如果有任何通过“insmod -fâ€è¢«å¼ºåˆ¶è£…载的模å—,' '如果所有模å—都被æ£å¸¸è£…载。 + + 3:'S'如果oopså‘生在SMPå†…æ ¸ä¸ï¼Œè¿è¡ŒäºŽæ²¡æœ‰è¯æ˜Žå®‰å…¨è¿è¡Œå¤šå¤„ç†å™¨çš„硬件。 当å‰è¿™ç§ +情况仅é™äºŽå‡ ç§ä¸æ”¯æŒSMP的速龙处ç†å™¨ã€‚ + + 4:'R'如果模å—通过“insmod -fâ€è¢«å¼ºåˆ¶è£…载,' '如果所有模å—都被æ£å¸¸è£…载。 + + 5:'M'如果任何处ç†å™¨æŠ¥å‘Šäº†æœºå™¨æ£€æŸ¥å¼‚常,' '如果没有å‘生机器检查异常。 + + 6:'B'如果页释放函数å‘现了一个错误的页引用或者一些éžé¢„æœŸçš„é¡µæ ‡å¿—ã€‚ + + 7:'U'如果用户或者用户应用程åºç‰¹åˆ«è¯·æ±‚è®¾ç½®æ±¡æŸ“æ ‡å¿—ï¼Œå¦åˆ™' '。 + + 8:'D'å¦‚æžœå†…æ ¸åˆšåˆšæ»æŽ‰ï¼Œæ¯”如有OOPS或者BUG。 + +使用'Tainted: 'å—符串的主è¦åŽŸå› 是è¦å‘Šè¯‰å†…æ ¸è°ƒè¯•è€…ï¼Œè¿™æ˜¯å¦æ˜¯ä¸€ä¸ªå¹²å‡€çš„å†…æ ¸äº¦æˆ–å‘ +生了任何的ä¸æ£å¸¸çš„事。污染是永久的:å³ä½¿å‡ºé”™çš„模å—å·²ç»è¢«å¸è½½äº†ï¼Œæ±¡æŸ“值ä»ç„¶å˜åœ¨ï¼Œ +ä»¥è¡¨æ˜Žå†…æ ¸ä¸å†å€¼å¾—信任。 diff --git a/Documentation/zh_CN/sparse.txt b/Documentation/zh_CN/sparse.txt new file mode 100644 index 0000000000000000000000000000000000000000..75992a603ae3664f5bfa3493c8e5de9072eadb7e --- /dev/null +++ b/Documentation/zh_CN/sparse.txt @@ -0,0 +1,100 @@ +Chinese translated version of Documentation/sparse.txt + +If you have any comment or update to the content, please contact the +original document maintainer directly. However, if you have a problem +communicating in English you can also ask the Chinese maintainer for +help. Contact the Chinese maintainer if this translation is outdated +or if there is a problem with the translation. + +Chinese maintainer: Li Yang <leo@zh-kernel.org> +--------------------------------------------------------------------- +Documentation/sparse.txt çš„ä¸æ–‡ç¿»è¯‘ + +如果想评论或更新本文的内容,请直接è”ç³»åŽŸæ–‡æ¡£çš„ç»´æŠ¤è€…ã€‚å¦‚æžœä½ ä½¿ç”¨è‹±æ–‡ +交æµæœ‰å›°éš¾çš„è¯ï¼Œä¹Ÿå¯ä»¥å‘ä¸æ–‡ç‰ˆç»´æŠ¤è€…求助。如果本翻译更新ä¸åŠæ—¶æˆ–者翻 +译å˜åœ¨é—®é¢˜ï¼Œè¯·è”ç³»ä¸æ–‡ç‰ˆç»´æŠ¤è€…。 + +ä¸æ–‡ç‰ˆç»´æŠ¤è€…: æŽé˜³ Li Yang <leo@zh-kernel.org> +ä¸æ–‡ç‰ˆç¿»è¯‘者: æŽé˜³ Li Yang <leo@zh-kernel.org> + + +以下为æ£æ–‡ +--------------------------------------------------------------------- + +Copyright 2004 Linus Torvalds +Copyright 2004 Pavel Machek <pavel@suse.cz> +Copyright 2006 Bob Copeland <me@bobcopeland.com> + +使用 sparse 工具åšç±»åž‹æ£€æŸ¥ +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +"__bitwise" 是一ç§ç±»åž‹å±žæ€§ï¼Œæ‰€ä»¥ä½ åº”è¯¥è¿™æ ·ä½¿ç”¨å®ƒï¼š + + typedef int __bitwise pm_request_t; + + enum pm_request { + PM_SUSPEND = (__force pm_request_t) 1, + PM_RESUME = (__force pm_request_t) 2 + }; + +è¿™æ ·ä¼šä½¿ PM_SUSPEND å’Œ PM_RESUME æˆä¸ºä½æ–¹å¼(bitwise)整数(使用"__force" +æ˜¯å› ä¸º sparse 会抱怨改å˜ä½æ–¹å¼çš„类型转æ¢ï¼Œä½†æ˜¯è¿™é‡Œæˆ‘们确实需è¦å¼ºåˆ¶è¿›è¡Œè½¬ +æ¢ï¼‰ã€‚è€Œä¸”å› ä¸ºæ‰€æœ‰æžšä¸¾å€¼éƒ½ä½¿ç”¨äº†ç›¸åŒçš„类型,这里的"enum pm_request"也将 +会使用那个类型åšä¸ºåº•å±‚实现。 + +而且使用 gcc 编译的时候,所有的 __bitwise/__force 都会消失,最åŽåœ¨ gcc +看æ¥å®ƒä»¬åªä¸è¿‡æ˜¯æ™®é€šçš„整数。 + +å¦ç™½æ¥è¯´ï¼Œä½ 并ä¸éœ€è¦ä½¿ç”¨æžšä¸¾ç±»åž‹ã€‚上é¢é‚£äº›å®žé™…都å¯ä»¥æµ“缩æˆä¸€ä¸ªç‰¹æ®Šçš„"int +__bitwise"类型。 + +所以更简å•çš„办法åªè¦è¿™æ ·åšï¼š + + typedef int __bitwise pm_request_t; + + #define PM_SUSPEND ((__force pm_request_t) 1) + #define PM_RESUME ((__force pm_request_t) 2) + +çŽ°åœ¨ä½ å°±æœ‰äº†ä¸¥æ ¼çš„ç±»åž‹æ£€æŸ¥æ‰€éœ€è¦çš„所有基础架构。 + +一个å°æ醒:常数整数"0"æ˜¯ç‰¹æ®Šçš„ã€‚ä½ å¯ä»¥ç›´æŽ¥æŠŠå¸¸æ•°é›¶å½“作ä½æ–¹å¼æ•´æ•°ä½¿ç”¨è€Œ +ä¸ç”¨æ‹…心 sparse ä¼šæŠ±æ€¨ã€‚è¿™æ˜¯å› ä¸º"bitwise"(æ°å¦‚å…¶å)是用æ¥ç¡®ä¿ä¸åŒä½æ–¹ +å¼ç±»åž‹ä¸ä¼šè¢«å¼„混(å°å°¾æ¨¡å¼ï¼Œå¤§å°¾æ¨¡å¼ï¼Œcpu尾模å¼ï¼Œæˆ–者其他),对他们æ¥è¯´ +常数"0"确实是特殊的。 + +èŽ·å– sparse 工具 +~~~~~~~~~~~~~~~~ + +ä½ å¯ä»¥ä»Ž Sparse 的主页获å–最新的å‘布版本: + + http://www.kernel.org/pub/linux/kernel/people/josh/sparse/ + +æˆ–è€…ï¼Œä½ ä¹Ÿå¯ä»¥ä½¿ç”¨ git 克隆最新的 sparse å¼€å‘版本: + + git://git.kernel.org/pub/scm/linux/kernel/git/josh/sparse.git + +DaveJ 把æ¯å°æ—¶è‡ªåŠ¨ç”Ÿæˆçš„ git æºç æ ‘ tar 包放在以下地å€ï¼š + + http://www.codemonkey.org.uk/projects/git-snapshots/sparse/ + +ä¸€æ—¦ä½ ä¸‹è½½äº†æºç ,åªè¦ä»¥æ™®é€šç”¨æˆ·èº«ä»½è¿è¡Œï¼š + + make + make install + +å®ƒå°†ä¼šè¢«è‡ªåŠ¨å®‰è£…åˆ°ä½ çš„ ~/bin 目录下。 + +使用 sparse 工具 +~~~~~~~~~~~~~~~~ + +用"make C=1"命令æ¥ç¼–è¯‘å†…æ ¸ï¼Œä¼šå¯¹æ‰€æœ‰é‡æ–°ç¼–译的 C 文件使用 sparse 工具。 +或者使用"make C=2"å‘½ä»¤ï¼Œæ— è®ºæ–‡ä»¶æ˜¯å¦è¢«é‡æ–°ç¼–译都会对其使用 sparse 工具。 +å¦‚æžœä½ å·²ç»ç¼–è¯‘äº†å†…æ ¸ï¼Œç”¨åŽä¸€ç§æ–¹å¼å¯ä»¥å¾ˆå¿«åœ°æ£€æŸ¥æ•´ä¸ªæºç æ ‘ã€‚ + +make çš„å¯é€‰å˜é‡ CHECKFLAGS å¯ä»¥ç”¨æ¥å‘ sparse å·¥å…·ä¼ é€’å‚数。编译系统会自 +åŠ¨å‘ sparse å·¥å…·ä¼ é€’ -Wbitwise å‚æ•°ã€‚ä½ å¯ä»¥å®šä¹‰ __CHECK_ENDIAN__ æ¥è¿›è¡Œ +大å°å°¾æ£€æŸ¥ã€‚ + + make C=2 CHECKFLAGS="-D__CHECK_ENDIAN__" + +这些检查默认都是被关é—çš„ï¼Œå› ä¸ºä»–ä»¬é€šå¸¸ä¼šäº§ç”Ÿå¤§é‡çš„è¦å‘Šã€‚ diff --git a/Documentation/zh_CN/stable_kernel_rules.txt b/Documentation/zh_CN/stable_kernel_rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..b5b9b0ab02fd5a76f1a67e8eb2de736ec7812f1e --- /dev/null +++ b/Documentation/zh_CN/stable_kernel_rules.txt @@ -0,0 +1,66 @@ +Chinese translated version of Documentation/stable_kernel_rules.txt + +If you have any comment or update to the content, please contact the +original document maintainer directly. However, if you have a problem +communicating in English you can also ask the Chinese maintainer for +help. Contact the Chinese maintainer if this translation is outdated +or if there is a problem with the translation. + +Chinese maintainer: TripleX Chung <triplex@zh-kernel.org> +--------------------------------------------------------------------- +Documentation/stable_kernel_rules.txt çš„ä¸æ–‡ç¿»è¯‘ + +如果想评论或更新本文的内容,请直接è”ç³»åŽŸæ–‡æ¡£çš„ç»´æŠ¤è€…ã€‚å¦‚æžœä½ ä½¿ç”¨è‹±æ–‡ +交æµæœ‰å›°éš¾çš„è¯ï¼Œä¹Ÿå¯ä»¥å‘ä¸æ–‡ç‰ˆç»´æŠ¤è€…求助。如果本翻译更新ä¸åŠæ—¶æˆ–者翻 +译å˜åœ¨é—®é¢˜ï¼Œè¯·è”ç³»ä¸æ–‡ç‰ˆç»´æŠ¤è€…。 + + +ä¸æ–‡ç‰ˆç»´æŠ¤è€…: 钟宇 TripleX Chung <triplex@zh-kernel.org> +ä¸æ–‡ç‰ˆç¿»è¯‘者: 钟宇 TripleX Chung <triplex@zh-kernel.org> +ä¸æ–‡ç‰ˆæ ¡è¯‘者: æŽé˜³ Li Yang <leo@zh-kernel.org> + Kangkai Yin <e12051@motorola.com> + +以下为æ£æ–‡ +--------------------------------------------------------------------- + +关于Linux 2.6稳定版å‘å¸ƒï¼Œæ‰€æœ‰ä½ æƒ³çŸ¥é“的事情。 + +关于哪些类型的补ä¸å¯ä»¥è¢«æŽ¥æ”¶è¿›å…¥ç¨³å®šç‰ˆä»£ç æ ‘ï¼Œå“ªäº›ä¸å¯ä»¥çš„规则: + + - 必须是显而易è§çš„æ£ç¡®ï¼Œå¹¶ä¸”ç»è¿‡æµ‹è¯•çš„。 + - è¿žåŒä¸Šä¸‹æ–‡ï¼Œä¸èƒ½å¤§äºŽ100行。 + - å¿…é¡»åªä¿®æ£ä¸€ä»¶äº‹æƒ…。 + - 必须修æ£äº†ä¸€ä¸ªç»™å¤§å®¶å¸¦æ¥éº»çƒ¦çš„真æ£çš„bug(ä¸æ˜¯â€œè¿™ä¹Ÿè®¸æ˜¯ä¸€ä¸ªé—®é¢˜...†+ é‚£æ ·çš„ä¸œè¥¿ï¼‰ã€‚ + - 必须修æ£å¸¦æ¥å¦‚下åŽæžœçš„é—®é¢˜ï¼šç¼–è¯‘é”™è¯¯ï¼ˆå¯¹è¢«æ ‡è®°ä¸ºCONFIG_BROKEN的例外), + å†…æ ¸å´©æºƒï¼ŒæŒ‚èµ·ï¼Œæ•°æ®æŸå,真æ£çš„å®‰å…¨é—®é¢˜ï¼Œæˆ–è€…ä¸€äº›ç±»ä¼¼â€œå“¦ï¼Œè¿™ä¸ + 好â€çš„问题。简çŸçš„说,就是一些致命的问题。 + - 没有“ç†è®ºä¸Šçš„竞争æ¡ä»¶â€ï¼Œé™¤éžèƒ½ç»™å‡ºç«žäº‰æ¡ä»¶å¦‚何被利用的解释。 + - ä¸èƒ½å˜åœ¨ä»»ä½•çš„“ç碎的â€ä¿®æ£ï¼ˆæ‹¼å†™ä¿®æ£ï¼ŒåŽ»æŽ‰å¤šä½™ç©ºæ ¼ä¹‹ç±»çš„)。 + - 必须被相关å系统的维护者接å—。 + - å¿…é¡»éµå¾ªDocumentation/SubmittingPatches里的规则。 + +å‘稳定版代ç æ ‘æ交补ä¸çš„过程: + + - 在确认了补ä¸ç¬¦åˆä»¥ä¸Šçš„规则åŽï¼Œå°†è¡¥ä¸å‘é€åˆ°stable@kernel.org。 + - 如果补ä¸è¢«æŽ¥å—到队列里,å‘é€è€…会收到一个ACK回å¤ï¼Œå¦‚果没有被接å—,收 + 到的是NAK回å¤ã€‚回å¤éœ€è¦å‡ 天的时间,这å–决于开å‘者的时间安排。 + - 被接å—çš„è¡¥ä¸ä¼šè¢«åŠ 到稳定版本队列里,ç‰å¾…其他开å‘者的审查。 + - 安全方é¢çš„è¡¥ä¸ä¸è¦å‘到这个列表,应该å‘é€åˆ°security@kernel.org。 + +审查周期: + + - 当稳定版的维护者决定开始一个审查周期,补ä¸å°†è¢«å‘é€åˆ°å®¡æŸ¥å§”员会,以 + åŠè¢«è¡¥ä¸å½±å“的领域的维护者(除éžæäº¤è€…å°±æ˜¯è¯¥é¢†åŸŸçš„ç»´æŠ¤è€…ï¼‰å¹¶ä¸”æŠ„é€ + 到linux-kernel邮件列表。 + - 审查委员会有48å°æ—¶çš„时间,用æ¥å†³å®šç»™è¯¥è¡¥ä¸å›žå¤ACK还是NAK。 + - 如果委员会ä¸æœ‰æˆå‘˜æ‹’ç»è¿™ä¸ªè¡¥ä¸ï¼Œæˆ–者linux-kernel列表上有人å对这个 + è¡¥ä¸ï¼Œå¹¶æ出维护者和审查委员会之å‰æ²¡æœ‰æ„识到的问题,补ä¸ä¼šä»Žé˜Ÿåˆ—ä¸ + 丢弃。 + - 在审查周期结æŸçš„时候,那些得到ACK回应的补ä¸å°†ä¼šè¢«åŠ 入到最新的稳定版 + å‘布ä¸ï¼Œä¸€ä¸ªæ–°çš„稳定版å‘布就æ¤äº§ç”Ÿã€‚ + - 安全性补ä¸å°†ä»Žå†…æ ¸å®‰å…¨å°ç»„那里直接接收到稳定版代ç æ ‘ä¸ï¼Œè€Œä¸æ˜¯é€šè¿‡ + 通常的审查周期。请è”ç³»å†…æ ¸å®‰å…¨å°ç»„以获得关于这个过程的更多细节。 + +审查委员会: + - ç”±ä¸€äº›è‡ªæ„¿æ‰¿æ‹…è¿™é¡¹ä»»åŠ¡çš„å†…æ ¸å¼€å‘è€…ï¼Œå’Œå‡ ä¸ªéžå¿—愿的组æˆã€‚ diff --git a/Documentation/zh_CN/volatile-considered-harmful.txt b/Documentation/zh_CN/volatile-considered-harmful.txt new file mode 100644 index 0000000000000000000000000000000000000000..ba8149d2233a048432193cb5b880e8331e23143e --- /dev/null +++ b/Documentation/zh_CN/volatile-considered-harmful.txt @@ -0,0 +1,113 @@ +Chinese translated version of Documentation/volatile-considered-harmful.txt + +If you have any comment or update to the content, please contact the +original document maintainer directly. However, if you have a problem +communicating in English you can also ask the Chinese maintainer for +help. Contact the Chinese maintainer if this translation is outdated +or if there is a problem with the translation. + +Maintainer: Jonathan Corbet <corbet@lwn.net> +Chinese maintainer: Bryan Wu <bryan.wu@analog.com> +--------------------------------------------------------------------- +Documentation/volatile-considered-harmful.txt çš„ä¸æ–‡ç¿»è¯‘ + +如果想评论或更新本文的内容,请直接è”ç³»åŽŸæ–‡æ¡£çš„ç»´æŠ¤è€…ã€‚å¦‚æžœä½ ä½¿ç”¨è‹±æ–‡ +交æµæœ‰å›°éš¾çš„è¯ï¼Œä¹Ÿå¯ä»¥å‘ä¸æ–‡ç‰ˆç»´æŠ¤è€…求助。如果本翻译更新ä¸åŠæ—¶æˆ–者翻 +译å˜åœ¨é—®é¢˜ï¼Œè¯·è”ç³»ä¸æ–‡ç‰ˆç»´æŠ¤è€…。 + +英文版维护者: Jonathan Corbet <corbet@lwn.net> +ä¸æ–‡ç‰ˆç»´æŠ¤è€…: ä¼é¹ Bryan Wu <bryan.wu@analog.com> +ä¸æ–‡ç‰ˆç¿»è¯‘者: ä¼é¹ Bryan Wu <bryan.wu@analog.com> +ä¸æ–‡ç‰ˆæ ¡è¯‘者: å¼ æ±‰è¾‰ Eugene Teo <eugeneteo@kernel.sg> + æ¨ç‘ž Dave Young <hidave.darkstar@gmail.com> +以下为æ£æ–‡ +--------------------------------------------------------------------- + +为什么ä¸åº”该使用“volatileâ€ç±»åž‹ +------------------------------ + +C程åºå‘˜é€šå¸¸è®¤ä¸ºvolatile表示æŸä¸ªå˜é‡å¯ä»¥åœ¨å½“å‰æ‰§è¡Œçš„线程之外被改å˜ï¼›å› æ¤ï¼Œåœ¨å†…æ ¸ +ä¸ç”¨åˆ°å…±äº«æ•°æ®ç»“构时,常常会有C程åºå‘˜å–œæ¬¢ä½¿ç”¨volatile这类å˜é‡ã€‚æ¢å¥è¯è¯´ï¼Œä»–ä»¬ç» +常会把volatile类型看æˆæŸç§ç®€æ˜“的原åå˜é‡ï¼Œå½“然它们ä¸æ˜¯ã€‚åœ¨å†…æ ¸ä¸ä½¿ç”¨volatileå‡ +ä¹Žæ€»æ˜¯é”™è¯¯çš„ï¼›æœ¬æ–‡æ¡£å°†è§£é‡Šä¸ºä»€ä¹ˆè¿™æ ·ã€‚ + +ç†è§£volatile的关键是知é“它的目的是用æ¥æ¶ˆé™¤ä¼˜åŒ–,实际上很少有人真æ£éœ€è¦è¿™æ ·çš„应 +ç”¨ã€‚åœ¨å†…æ ¸ä¸ï¼Œç¨‹åºå‘˜å¿…须防æ¢æ„外的并å‘è®¿é—®ç ´å共享的数æ®ç»“构,这其实是一个完全 +ä¸åŒçš„任务。用æ¥é˜²æ¢æ„外并å‘访问的ä¿æŠ¤æŽªæ–½ï¼Œå¯ä»¥æ›´åŠ 高效的é¿å…大多数优化相关的 +问题。 + +åƒvolatileä¸€æ ·ï¼Œå†…æ ¸æ供了很多原è¯æ¥ä¿è¯å¹¶å‘访问时的数æ®å®‰å…¨ï¼ˆè‡ªæ—‹é”, 互斥é‡,内 +å˜å±éšœç‰ç‰ï¼‰ï¼ŒåŒæ ·å¯ä»¥é˜²æ¢æ„外的优化。如果å¯ä»¥æ£ç¡®ä½¿ç”¨è¿™äº›å†…æ ¸åŽŸè¯ï¼Œé‚£ä¹ˆå°±æ²¡æœ‰ +å¿…è¦å†ä½¿ç”¨volatile。如果ä»ç„¶å¿…须使用volatileï¼Œé‚£ä¹ˆå‡ ä¹Žå¯ä»¥è‚¯å®šåœ¨ä»£ç çš„æŸå¤„有一 +个bug。在æ£ç¡®è®¾è®¡çš„å†…æ ¸ä»£ç ä¸ï¼Œvolatile能带æ¥çš„仅仅是使事情å˜æ…¢ã€‚ + +æ€è€ƒä¸€ä¸‹è¿™æ®µå…¸åž‹çš„å†…æ ¸ä»£ç : + + spin_lock(&the_lock); + do_something_on(&shared_data); + do_something_else_with(&shared_data); + spin_unlock(&the_lock); + +如果所有的代ç 都éµå¾ªåŠ é”规则,当æŒæœ‰the_lock的时候,ä¸å¯èƒ½æ„外的改å˜shared_dataçš„ +值。任何å¯èƒ½è®¿é—®è¯¥æ•°æ®çš„其他代ç 都会在这个é”上ç‰å¾…。自旋é”原è¯è·Ÿå†…å˜å±éšœä¸€æ ·â€”— 它 +们显å¼çš„用æ¥ä¹¦å†™æˆè¿™æ · —— æ„味ç€æ•°æ®è®¿é—®ä¸ä¼šè·¨è¶Šå®ƒä»¬è€Œè¢«ä¼˜åŒ–。所以本æ¥ç¼–译器认为 +它知é“在shared_data里é¢å°†æœ‰ä»€ä¹ˆï¼Œä½†æ˜¯å› 为spin_lock()调用跟内å˜å±éšœä¸€æ ·ï¼Œä¼šå¼ºåˆ¶ç¼– +译器忘记它所知é“的一切。那么在访问这些数æ®æ—¶ä¸ä¼šæœ‰ä¼˜åŒ–的问题。 + +如果shared_data被声å为volatile,é”æ“作将ä»ç„¶æ˜¯å¿…须的。就算我们知é“没有其他人æ£åœ¨ +使用它,编译器也将被阻æ¢ä¼˜åŒ–对临界区内shared_data的访问。在é”有效的åŒæ—¶ï¼Œ +shared_dataä¸æ˜¯volatile的。在处ç†å…±äº«æ•°æ®çš„时候,适当的é”æ“作å¯ä»¥ä¸å†éœ€è¦ +volatile —— 并且是有潜在å±å®³çš„。 + +volatileçš„å˜å‚¨ç±»åž‹æœ€åˆæ˜¯ä¸ºé‚£äº›å†…å˜æ˜ å°„çš„I/O寄å˜å™¨è€Œå®šä¹‰ã€‚åœ¨å†…æ ¸é‡Œï¼Œå¯„å˜å™¨è®¿é—®ä¹Ÿåº” +该被é”ä¿æŠ¤ï¼Œä½†æ˜¯äººä»¬ä¹Ÿä¸å¸Œæœ›ç¼–译器“优化â€ä¸´ç•ŒåŒºå†…的寄å˜å™¨è®¿é—®ã€‚å†…æ ¸é‡ŒI/O的内å˜è®¿é—® +是通过访问函数完æˆçš„ï¼›ä¸èµžæˆé€šè¿‡æŒ‡é’ˆå¯¹I/O内å˜çš„直接访问,并且ä¸æ˜¯åœ¨æ‰€æœ‰ä½“系架构上 +都能工作。那些访问函数æ£æ˜¯ä¸ºäº†é˜²æ¢æ„å¤–ä¼˜åŒ–è€Œå†™çš„ï¼Œå› æ¤ï¼Œå†è¯´ä¸€æ¬¡ï¼Œvolatileç±»åž‹ä¸ +是必需的。 + +å¦ä¸€ç§å¼•èµ·ç”¨æˆ·å¯èƒ½ä½¿ç”¨volatile的情况是当处ç†å™¨æ£å¿™ç€ç‰å¾…一个å˜é‡çš„值。æ£ç¡®æ‰§è¡Œä¸€ +个忙ç‰å¾…的方法是: + + while (my_variable != what_i_want) + cpu_relax(); + +cpu_relax()调用会é™ä½ŽCPU的能é‡æ¶ˆè€—或者让ä½äºŽè¶…线程åŒå¤„ç†å™¨ï¼›å®ƒä¹Ÿä½œä¸ºå†…å˜å±éšœä¸€æ ·å‡º +现,所以,å†ä¸€æ¬¡ï¼Œvolatileä¸æ˜¯å¿…需的。当然,忙ç‰å¾…一开始就是一ç§å常规的åšæ³•ã€‚ + +åœ¨å†…æ ¸ä¸ï¼Œä¸€äº›ç¨€å°‘的情况下volatileä»ç„¶æ˜¯æœ‰æ„义的: + + - 在一些体系架构的系统上,å…许直接的I/0内å˜è®¿é—®ï¼Œé‚£ä¹ˆå‰é¢æ到的访问函数å¯ä»¥ä½¿ç”¨ + volatile。基本上,æ¯ä¸€ä¸ªè®¿é—®å‡½æ•°è°ƒç”¨å®ƒè‡ªå·±éƒ½æ˜¯ä¸€ä¸ªå°çš„临界区域并且ä¿è¯äº†æŒ‰ç…§ + 程åºå‘˜æœŸæœ›çš„é‚£æ ·å‘生访问æ“作。 + + - æŸäº›ä¼šæ”¹å˜å†…å˜çš„内è”汇编代ç 虽然没有什么其他明显的附作用,但是有被GCCåˆ é™¤çš„å¯ + 能性。在汇编声明ä¸åŠ 上volatile关键å—å¯ä»¥é˜²æ¢è¿™ç§åˆ 除æ“作。 + + - Jiffieså˜é‡æ˜¯ä¸€ç§ç‰¹æ®Šæƒ…况,虽然æ¯æ¬¡å¼•ç”¨å®ƒçš„时候都å¯ä»¥æœ‰ä¸åŒçš„值,但读jiffies + å˜é‡æ—¶ä¸éœ€è¦ä»»ä½•ç‰¹æ®Šçš„åŠ é”ä¿æŠ¤ã€‚所以jiffieså˜é‡å¯ä»¥ä½¿ç”¨volatile,但是ä¸èµžæˆ + 其他跟jiffies相åŒç±»åž‹å˜é‡ä½¿ç”¨volatile。Jiffies被认为是一ç§â€œæ„šè ¢çš„é—留物" + (Linusçš„è¯ï¼‰å› 为解决这个问题比ä¿æŒçŽ°çŠ¶è¦éº»çƒ¦çš„多。 + + - 由于æŸäº›I/0设备å¯èƒ½ä¼šä¿®æ”¹è¿žç»ä¸€è‡´çš„内å˜,所以有时,指å‘è¿žç»ä¸€è‡´å†…å˜çš„æ•°æ®ç»“æž„ + 的指针需è¦æ£ç¡®çš„使用volatile。网络适é…器使用的环状缓å˜åŒºæ£æ˜¯è¿™ç±»æƒ…形的一个例 + å,其ä¸é€‚é…器用改å˜æŒ‡é’ˆæ¥è¡¨ç¤ºå“ªäº›æ述符已ç»å¤„ç†è¿‡äº†ã€‚ + +对于大多代ç ï¼Œä¸Šè¿°å‡ ç§å¯ä»¥ä½¿ç”¨volatile的情况都ä¸é€‚用。所以,使用volatileæ˜¯ä¸€ç§ +bug并且需è¦å¯¹è¿™æ ·çš„代ç é¢å¤–仔细检查。那些试图使用volatileçš„å¼€å‘人员需è¦é€€ä¸€æ¥æƒ³æƒ³ +他们真æ£æƒ³å®žçŽ°çš„是什么。 + +éžå¸¸æ¬¢è¿Žåˆ 除volatileå˜é‡çš„è¡¥ä¸ ï¼ åªè¦è¯æ˜Žè¿™äº›è¡¥ä¸å®Œæ•´çš„考虑了并å‘问题。 + +注释 +---- + +[1] http://lwn.net/Articles/233481/ +[2] http://lwn.net/Articles/233482/ + +致谢 +---- + +最åˆç”±Randy Dunlap推动并作åˆæ¥ç ”究 +ç”±Jonathan Corbet撰写 +å‚考Satyam Sharma,Johannes Stezenbach,Jesper Juhl,Heikki Orsila, +H. Peter Anvin,Philipp Hahnå’ŒStefan Richterçš„æ„è§æ”¹å–„了本档。 diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index 1533d3ecd7a05b71b559f56356560a37daabefcf..f6f3689a86ee2e10b99e7dfca154c98713b16971 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -195,7 +195,7 @@ static int leds_shutdown(struct sys_device *dev) } static struct sysdev_class leds_sysclass = { - set_kset_name("leds"), + .name = "leds", .shutdown = leds_shutdown, .suspend = leds_suspend, .resume = leds_resume, @@ -369,7 +369,7 @@ static int timer_resume(struct sys_device *dev) #endif static struct sysdev_class timer_sysclass = { - set_kset_name("timer"), + .name = "timer", .suspend = timer_suspend, .resume = timer_resume, }; diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index 72280754354d3b98e7785c945abd0ec33930202c..df37e93c6fc92e51826fbf1c669c585b5d5d105f 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c @@ -214,7 +214,7 @@ static int irq_resume(struct sys_device *dev) #endif static struct sysdev_class irq_class = { - set_kset_name("irq"), + .name = "irq", .suspend = irq_suspend, .resume = irq_resume, }; diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c index 3bf01e28df334ceaaf49dc55c8d4cd59e00c09d4..d9805e3d930400de42e49afd8216e3a8c71bb745 100644 --- a/arch/arm/mach-omap1/pm.c +++ b/arch/arm/mach-omap1/pm.c @@ -69,14 +69,14 @@ static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE]; static unsigned short enable_dyn_sleep = 1; -static ssize_t omap_pm_sleep_while_idle_show(struct kset *kset, char *buf) +static ssize_t idle_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) { return sprintf(buf, "%hu\n", enable_dyn_sleep); } -static ssize_t omap_pm_sleep_while_idle_store(struct kset *kset, - const char * buf, - size_t n) +static ssize_t idle_store(struct kobject *kobj, struct kobj_attribute *attr, + const char * buf, size_t n) { unsigned short value; if (sscanf(buf, "%hu", &value) != 1 || @@ -88,16 +88,9 @@ static ssize_t omap_pm_sleep_while_idle_store(struct kset *kset, return n; } -static struct subsys_attribute sleep_while_idle_attr = { - .attr = { - .name = __stringify(sleep_while_idle), - .mode = 0644, - }, - .show = omap_pm_sleep_while_idle_show, - .store = omap_pm_sleep_while_idle_store, -}; +static struct kobj_attribute sleep_while_idle_attr = + __ATTR(sleep_while_idle, 0644, idle_show, idle_store); -extern struct kset power_subsys; static void (*omap_sram_idle)(void) = NULL; static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL; @@ -726,9 +719,9 @@ static int __init omap_pm_init(void) omap_pm_init_proc(); #endif - error = subsys_create_file(&power_subsys, &sleep_while_idle_attr); + error = sysfs_create_file(power_kobj, &sleep_while_idle_attr); if (error) - printk(KERN_ERR "subsys_create_file failed: %d\n", error); + printk(KERN_ERR "sysfs_create_file failed: %d\n", error); if (cpu_is_omap16xx()) { /* configure LOW_PWR pin */ diff --git a/arch/arm/mach-pxa/cm-x270.c b/arch/arm/mach-pxa/cm-x270.c index 177664ccb2e230ab954fcbbdbf9913a6de499d88..a16349272f54db89e1c7fbfa1a846c57f2430047 100644 --- a/arch/arm/mach-pxa/cm-x270.c +++ b/arch/arm/mach-pxa/cm-x270.c @@ -566,7 +566,7 @@ static int cmx270_resume(struct sys_device *dev) } static struct sysdev_class cmx270_pm_sysclass = { - set_kset_name("pm"), + .name = "pm", .resume = cmx270_resume, .suspend = cmx270_suspend, }; diff --git a/arch/arm/mach-pxa/lpd270.c b/arch/arm/mach-pxa/lpd270.c index 26116440a7c927648d7b8a3e493bdf042cab3beb..78ebad063cba59bb9ef58ddb8918869411cc9e87 100644 --- a/arch/arm/mach-pxa/lpd270.c +++ b/arch/arm/mach-pxa/lpd270.c @@ -122,7 +122,7 @@ static int lpd270_irq_resume(struct sys_device *dev) } static struct sysdev_class lpd270_irq_sysclass = { - set_kset_name("cpld_irq"), + .name = "cpld_irq", .resume = lpd270_irq_resume, }; diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index 011a1a72b61c87241d15f3515facfb9c7917cd3f..1d3112dc629ea38a76f203adac5f96affe6b0f20 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c @@ -126,7 +126,7 @@ static int lubbock_irq_resume(struct sys_device *dev) } static struct sysdev_class lubbock_irq_sysclass = { - set_kset_name("cpld_irq"), + .name = "cpld_irq", .resume = lubbock_irq_resume, }; diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c index a4bc3483cbb3f29540739f5268dedc02b21f7972..41d8c6cea62b4d26285f22a9eb23479bdcc5a501 100644 --- a/arch/arm/mach-pxa/mainstone.c +++ b/arch/arm/mach-pxa/mainstone.c @@ -120,7 +120,7 @@ static int mainstone_irq_resume(struct sys_device *dev) } static struct sysdev_class mainstone_irq_sysclass = { - set_kset_name("cpld_irq"), + .name = "cpld_irq", .resume = mainstone_irq_resume, }; diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c index e580303cb0abbd86d1e97429ea21fceaeeb0efec..0e7991940f81b040c88ca73d5501038c3d69fbc8 100644 --- a/arch/arm/mach-s3c2410/s3c2410.c +++ b/arch/arm/mach-s3c2410/s3c2410.c @@ -100,7 +100,7 @@ void __init s3c2410_init_clocks(int xtal) } struct sysdev_class s3c2410_sysclass = { - set_kset_name("s3c2410-core"), + .name = "s3c2410-core", }; static struct sys_device s3c2410_sysdev = { diff --git a/arch/arm/mach-s3c2412/s3c2412.c b/arch/arm/mach-s3c2412/s3c2412.c index 4f92a1562d77fa62043e5d4a29679a8d928a612d..265cd3f567a3fe164bbe9027cd2856120e725dd9 100644 --- a/arch/arm/mach-s3c2412/s3c2412.c +++ b/arch/arm/mach-s3c2412/s3c2412.c @@ -196,7 +196,7 @@ void __init s3c2412_init_clocks(int xtal) */ struct sysdev_class s3c2412_sysclass = { - set_kset_name("s3c2412-core"), + .name = "s3c2412-core", }; static int __init s3c2412_core_init(void) diff --git a/arch/arm/mach-s3c2440/mach-osiris.c b/arch/arm/mach-s3c2440/mach-osiris.c index c326983f4a8f5b66dcee243def28998c560d2bb2..78af7664988b98746f1499a79dd142a0fb33b5fd 100644 --- a/arch/arm/mach-s3c2440/mach-osiris.c +++ b/arch/arm/mach-s3c2440/mach-osiris.c @@ -312,7 +312,7 @@ static int osiris_pm_resume(struct sys_device *sd) #endif static struct sysdev_class osiris_pm_sysclass = { - set_kset_name("mach-osiris"), + .name = "mach-osiris", .suspend = osiris_pm_suspend, .resume = osiris_pm_resume, }; diff --git a/arch/arm/mach-s3c2443/s3c2443.c b/arch/arm/mach-s3c2443/s3c2443.c index 8d8117158d23aa5d9e22b59bbd7db5abfe67d805..9ce490560af98df561a7742a858515c17cc063fd 100644 --- a/arch/arm/mach-s3c2443/s3c2443.c +++ b/arch/arm/mach-s3c2443/s3c2443.c @@ -43,7 +43,7 @@ static struct map_desc s3c2443_iodesc[] __initdata = { }; struct sysdev_class s3c2443_sysclass = { - set_kset_name("s3c2443-core"), + .name = "s3c2443-core", }; static struct sys_device s3c2443_sysdev = { diff --git a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c index edf3347d9c5b61bccce6859cc0fcde6fc935964b..3dc17d7bf38e823f407c05e30f1af20d8ae2022d 100644 --- a/arch/arm/mach-sa1100/irq.c +++ b/arch/arm/mach-sa1100/irq.c @@ -283,7 +283,7 @@ static int sa1100irq_resume(struct sys_device *dev) } static struct sysdev_class sa1100irq_sysclass = { - set_kset_name("sa11x0-irq"), + .name = "sa11x0-irq", .suspend = sa1100irq_suspend, .resume = sa1100irq_resume, }; diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c index a9de727c9327aa29eb266e45860a681e72f1d55c..0a5cf3a6438be268f792ae0cb1ec9d7c6a66692c 100644 --- a/arch/arm/oprofile/common.c +++ b/arch/arm/oprofile/common.c @@ -96,7 +96,7 @@ static int op_arm_resume(struct sys_device *dev) } static struct sysdev_class oprofile_sysclass = { - set_kset_name("oprofile"), + .name = "oprofile", .resume = op_arm_resume, .suspend = op_arm_suspend, }; diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index 6097753394adaef923105fe47a6b6237fc1a27f7..b2a87b8ef6734e95a3fa207a357bb5c0ecde96bd 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -1455,7 +1455,7 @@ static int omap_gpio_resume(struct sys_device *dev) } static struct sysdev_class omap_gpio_sysclass = { - set_kset_name("gpio"), + .name = "gpio", .suspend = omap_gpio_suspend, .resume = omap_gpio_resume, }; diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c index 29696e46ed659bab0fdb00cc5fc0f17aaf8f1040..aae1b9cbaf44b77a0e9f4ea7e9f37c04cd1a1191 100644 --- a/arch/arm/plat-s3c24xx/dma.c +++ b/arch/arm/plat-s3c24xx/dma.c @@ -1265,7 +1265,7 @@ static int s3c2410_dma_resume(struct sys_device *dev) #endif /* CONFIG_PM */ struct sysdev_class dma_sysclass = { - set_kset_name("s3c24xx-dma"), + .name = "s3c24xx-dma", .suspend = s3c2410_dma_suspend, .resume = s3c2410_dma_resume, }; diff --git a/arch/arm/plat-s3c24xx/s3c244x.c b/arch/arm/plat-s3c24xx/s3c244x.c index 3444b13afac52ad0a9694785f204f50c71c32ade..f197bb3a2366c980e6cf66d2042b7c19c524f4ee 100644 --- a/arch/arm/plat-s3c24xx/s3c244x.c +++ b/arch/arm/plat-s3c24xx/s3c244x.c @@ -151,13 +151,13 @@ static int s3c244x_resume(struct sys_device *dev) /* Since the S3C2442 and S3C2440 share items, put both sysclasses here */ struct sysdev_class s3c2440_sysclass = { - set_kset_name("s3c2440-core"), + .name = "s3c2440-core", .suspend = s3c244x_suspend, .resume = s3c244x_resume }; struct sysdev_class s3c2442_sysclass = { - set_kset_name("s3c2442-core"), + .name = "s3c2442-core", .suspend = s3c244x_suspend, .resume = s3c244x_resume }; diff --git a/arch/avr32/kernel/time.c b/arch/avr32/kernel/time.c index 7014a3571ec024a5cdccc4161817ceb73401013b..36a46c3ae30880c8f2b478f6c9df7c2d84b27247 100644 --- a/arch/avr32/kernel/time.c +++ b/arch/avr32/kernel/time.c @@ -214,7 +214,7 @@ void __init time_init(void) } static struct sysdev_class timer_class = { - set_kset_name("timer"), + .name = "timer", }; static struct sys_device timer_device = { diff --git a/arch/cris/arch-v32/drivers/iop_fw_load.c b/arch/cris/arch-v32/drivers/iop_fw_load.c index 11f9895ded5056d4b51192c06c3726433beed1ed..f4bdc1dfa3204f931cfbbda7b9442524874b258b 100644 --- a/arch/cris/arch-v32/drivers/iop_fw_load.c +++ b/arch/cris/arch-v32/drivers/iop_fw_load.c @@ -20,6 +20,9 @@ #define IOP_TIMEOUT 100 +#error "This driver is broken with regard to its driver core usage." +#error "Please contact <greg@kroah.com> for details on how to fix it properly." + static struct device iop_spu_device[2] = { { .bus_id = "iop-spu0", }, { .bus_id = "iop-spu1", }, @@ -192,6 +195,13 @@ int iop_start_mpu(unsigned int start_addr) static int __init iop_fw_load_init(void) { +#if 0 + /* + * static struct devices can not be added directly to sysfs by ignoring + * the driver model infrastructure. To fix this properly, please use + * the platform_bus to register these devices to be able to properly + * use the firmware infrastructure. + */ device_initialize(&iop_spu_device[0]); kobject_set_name(&iop_spu_device[0].kobj, "iop-spu0"); kobject_add(&iop_spu_device[0].kobj); @@ -201,6 +211,7 @@ static int __init iop_fw_load_init(void) device_initialize(&iop_mpu_device); kobject_set_name(&iop_mpu_device.kobj, "iop-mpu"); kobject_add(&iop_mpu_device.kobj); +#endif return 0; } diff --git a/arch/ia64/kernel/topology.c b/arch/ia64/kernel/topology.c index 14261fee5f4dbdb1ef88beb9b02c2dbf41906151..a2484fc1a06c43482e575888ca1991d45faf43e7 100644 --- a/arch/ia64/kernel/topology.c +++ b/arch/ia64/kernel/topology.c @@ -354,27 +354,27 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev) if (unlikely(retval < 0)) return retval; - all_cpu_cache_info[cpu].kobj.parent = &sys_dev->kobj; - kobject_set_name(&all_cpu_cache_info[cpu].kobj, "%s", "cache"); - all_cpu_cache_info[cpu].kobj.ktype = &cache_ktype_percpu_entry; - retval = kobject_register(&all_cpu_cache_info[cpu].kobj); + retval = kobject_init_and_add(&all_cpu_cache_info[cpu].kobj, + &cache_ktype_percpu_entry, &sys_dev->kobj, + "%s", "cache"); for (i = 0; i < all_cpu_cache_info[cpu].num_cache_leaves; i++) { this_object = LEAF_KOBJECT_PTR(cpu,i); - this_object->kobj.parent = &all_cpu_cache_info[cpu].kobj; - kobject_set_name(&(this_object->kobj), "index%1lu", i); - this_object->kobj.ktype = &cache_ktype; - retval = kobject_register(&(this_object->kobj)); + retval = kobject_init_and_add(&(this_object->kobj), + &cache_ktype, + &all_cpu_cache_info[cpu].kobj, + "index%1lu", i); if (unlikely(retval)) { for (j = 0; j < i; j++) { - kobject_unregister( - &(LEAF_KOBJECT_PTR(cpu,j)->kobj)); + kobject_put(&(LEAF_KOBJECT_PTR(cpu,j)->kobj)); } - kobject_unregister(&all_cpu_cache_info[cpu].kobj); + kobject_put(&all_cpu_cache_info[cpu].kobj); cpu_cache_sysfs_exit(cpu); break; } + kobject_uevent(&(this_object->kobj), KOBJ_ADD); } + kobject_uevent(&all_cpu_cache_info[cpu].kobj, KOBJ_ADD); return retval; } @@ -385,10 +385,10 @@ static int __cpuinit cache_remove_dev(struct sys_device * sys_dev) unsigned long i; for (i = 0; i < all_cpu_cache_info[cpu].num_cache_leaves; i++) - kobject_unregister(&(LEAF_KOBJECT_PTR(cpu,i)->kobj)); + kobject_put(&(LEAF_KOBJECT_PTR(cpu,i)->kobj)); if (all_cpu_cache_info[cpu].kobj.parent) { - kobject_unregister(&all_cpu_cache_info[cpu].kobj); + kobject_put(&all_cpu_cache_info[cpu].kobj); memset(&all_cpu_cache_info[cpu].kobj, 0, sizeof(struct kobject)); diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c index 4710135771085dd658cd69e5e9553e609c42acb8..197d7977de356e603465f62e780f945eb3dbe16f 100644 --- a/arch/mips/kernel/i8259.c +++ b/arch/mips/kernel/i8259.c @@ -238,7 +238,7 @@ static int i8259A_shutdown(struct sys_device *dev) } static struct sysdev_class i8259_sysdev_class = { - set_kset_name("i8259"), + .name = "i8259", .resume = i8259A_resume, .shutdown = i8259A_shutdown, }; diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index c83c3e3f51784c55a3ed85f4e67e2e2513cec2f3..a088622036437e8a64c9be58f73e8606c0bb5db5 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -459,7 +459,7 @@ static int spu_shutdown(struct sys_device *sysdev) } static struct sysdev_class spu_sysdev_class = { - set_kset_name("spu"), + .name = "spu", .shutdown = spu_shutdown, }; diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 999f5e160897ba23ba07d7b6ae766d028fa26a7e..84c0d4ef76a2d1c3c88b744a56d0ce2c14cb5c9e 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -663,7 +663,7 @@ static int pmacpic_resume(struct sys_device *sysdev) #endif /* CONFIG_PM && CONFIG_PPC32 */ static struct sysdev_class pmacpic_sysclass = { - set_kset_name("pmac_pic"), + .name = "pmac_pic", }; static struct sys_device device_pmacpic = { diff --git a/arch/powerpc/platforms/pseries/power.c b/arch/powerpc/platforms/pseries/power.c index 73e69023d90a9f57b76a718c910dde2aa3b24f0b..e95fc1594c84b0d8f76c351c459ce8b74b2db816 100644 --- a/arch/powerpc/platforms/pseries/power.c +++ b/arch/powerpc/platforms/pseries/power.c @@ -28,13 +28,15 @@ unsigned long rtas_poweron_auto; /* default and normal state is 0 */ -static ssize_t auto_poweron_show(struct kset *kset, char *buf) +static ssize_t auto_poweron_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { return sprintf(buf, "%lu\n", rtas_poweron_auto); } -static ssize_t -auto_poweron_store(struct kset *kset, const char *buf, size_t n) +static ssize_t auto_poweron_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t n) { int ret; unsigned long ups_restart; @@ -47,17 +49,11 @@ auto_poweron_store(struct kset *kset, const char *buf, size_t n) return -EINVAL; } -static struct subsys_attribute auto_poweron_attr = { - .attr = { - .name = __stringify(auto_poweron), - .mode = 0644, - }, - .show = auto_poweron_show, - .store = auto_poweron_store, -}; +static struct kobj_attribute auto_poweron_attr = + __ATTR(auto_poweron, 0644, auto_poweron_show, auto_poweron_store); #ifndef CONFIG_PM -decl_subsys(power,NULL,NULL); +struct kobject *power_kobj; static struct attribute *g[] = { &auto_poweron_attr.attr, @@ -70,18 +66,16 @@ static struct attribute_group attr_group = { static int __init pm_init(void) { - int error = subsystem_register(&power_subsys); - if (!error) - error = sysfs_create_group(&power_subsys.kobj, &attr_group); - return error; + power_kobj = kobject_create_and_add("power", NULL); + if (!power_kobj) + return -ENOMEM; + return sysfs_create_group(power_kobj, &attr_group); } core_initcall(pm_init); #else -extern struct kset power_subsys; - static int __init apo_pm_init(void) { - return (subsys_create_file(&power_subsys, &auto_poweron_attr)); + return (sysfs_create_file(power_kobj, &auto_poweron_attr)); } __initcall(apo_pm_init); #endif diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c index 05a56e55804c3ab4395671b9bd2a4713972cbf20..e898ff4d2b97c9218e2bbb0793e21df86d5b5d28 100644 --- a/arch/powerpc/sysdev/ipic.c +++ b/arch/powerpc/sysdev/ipic.c @@ -725,7 +725,7 @@ unsigned int ipic_get_irq(void) } static struct sysdev_class ipic_sysclass = { - set_kset_name("ipic"), + .name = "ipic", }; static struct sys_device device_ipic = { diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index e47938899a9268c3e926979f7f15e73394810c3d..212a94f5d34b5e6d20ca4169e6014de284a87ebe 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -1584,7 +1584,7 @@ static struct sysdev_class mpic_sysclass = { .resume = mpic_resume, .suspend = mpic_suspend, #endif - set_kset_name("mpic"), + .name = "mpic", }; static int mpic_init_sys(void) diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c index e1c0fd6dbc1aaf23400cc385d946602de5831d2d..f59444d3be752aa9580d751a9a76c0cd008a5f85 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_ic.c +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c @@ -483,7 +483,7 @@ int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high) } static struct sysdev_class qe_ic_sysclass = { - set_kset_name("qe_ic"), + .name = "qe_ic", }; static struct sys_device device_qe_ic = { diff --git a/arch/ppc/syslib/ipic.c b/arch/ppc/syslib/ipic.c index 9192777d0f78469c9791970327a2b97f4d7d47c8..4f163e20939e2ba94feb6f70a48ad72bed03bdf9 100644 --- a/arch/ppc/syslib/ipic.c +++ b/arch/ppc/syslib/ipic.c @@ -614,7 +614,7 @@ int ipic_get_irq(void) } static struct sysdev_class ipic_sysclass = { - set_kset_name("ipic"), + .name = "ipic", }; static struct sys_device device_ipic = { diff --git a/arch/ppc/syslib/open_pic.c b/arch/ppc/syslib/open_pic.c index 18ec94733293538228d97f311d9e50003f28540a..da36522d327a778fbf4921bbd099a5cefb85af46 100644 --- a/arch/ppc/syslib/open_pic.c +++ b/arch/ppc/syslib/open_pic.c @@ -1043,7 +1043,7 @@ int openpic_resume(struct sys_device *sysdev) #endif /* CONFIG_PM */ static struct sysdev_class openpic_sysclass = { - set_kset_name("openpic"), + .name = "openpic", }; static struct sys_device device_openpic = { diff --git a/arch/ppc/syslib/open_pic2.c b/arch/ppc/syslib/open_pic2.c index d585207f9f77855e0c8f126dfc52014fbc4328af..449075a0479803f9c17d52fc240f8dbeffcf4478 100644 --- a/arch/ppc/syslib/open_pic2.c +++ b/arch/ppc/syslib/open_pic2.c @@ -666,7 +666,7 @@ int openpic2_resume(struct sys_device *sysdev) /* HACK ALERT */ static struct sysdev_class openpic2_sysclass = { - set_kset_name("openpic2"), + .name = "openpic2", }; static struct sys_device device_openpic2 = { diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index 5245717295b82f5e9a42d07af8a6c160c6367cbf..4b010ff814c9caa3f439cb7e849aa8c501bdace1 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -490,7 +490,7 @@ static struct super_operations hypfs_s_ops = { .show_options = hypfs_show_options, }; -static decl_subsys(s390, NULL, NULL); +static struct kobject *s390_kobj; static int __init hypfs_init(void) { @@ -506,17 +506,18 @@ static int __init hypfs_init(void) goto fail_diag; } } - kobj_set_kset_s(&s390_subsys, hypervisor_subsys); - rc = subsystem_register(&s390_subsys); - if (rc) + s390_kobj = kobject_create_and_add("s390", hypervisor_kobj); + if (!s390_kobj) { + rc = -ENOMEM;; goto fail_sysfs; + } rc = register_filesystem(&hypfs_type); if (rc) goto fail_filesystem; return 0; fail_filesystem: - subsystem_unregister(&s390_subsys); + kobject_put(s390_kobj); fail_sysfs: if (!MACHINE_IS_VM) hypfs_diag_exit(); @@ -530,7 +531,7 @@ static void __exit hypfs_exit(void) if (!MACHINE_IS_VM) hypfs_diag_exit(); unregister_filesystem(&hypfs_type); - subsystem_unregister(&s390_subsys); + kobject_put(s390_kobj); } module_init(hypfs_init) diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index ce0856d32500215ef1942d03a0a61f000767d4fa..b97694fa62ecb26377db4e3a5349e50e68042979 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -162,22 +162,25 @@ EXPORT_SYMBOL_GPL(diag308); /* SYSFS */ #define DEFINE_IPL_ATTR_RO(_prefix, _name, _format, _value) \ -static ssize_t sys_##_prefix##_##_name##_show(struct kset *kset, \ +static ssize_t sys_##_prefix##_##_name##_show(struct kobject *kobj, \ + struct kobj_attribute *attr, \ char *page) \ { \ return sprintf(page, _format, _value); \ } \ -static struct subsys_attribute sys_##_prefix##_##_name##_attr = \ +static struct kobj_attribute sys_##_prefix##_##_name##_attr = \ __ATTR(_name, S_IRUGO, sys_##_prefix##_##_name##_show, NULL); #define DEFINE_IPL_ATTR_RW(_prefix, _name, _fmt_out, _fmt_in, _value) \ -static ssize_t sys_##_prefix##_##_name##_show(struct kset *kset, \ +static ssize_t sys_##_prefix##_##_name##_show(struct kobject *kobj, \ + struct kobj_attribute *attr, \ char *page) \ { \ return sprintf(page, _fmt_out, \ (unsigned long long) _value); \ } \ -static ssize_t sys_##_prefix##_##_name##_store(struct kset *kset, \ +static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj, \ + struct kobj_attribute *attr, \ const char *buf, size_t len) \ { \ unsigned long long value; \ @@ -186,25 +189,27 @@ static ssize_t sys_##_prefix##_##_name##_store(struct kset *kset, \ _value = value; \ return len; \ } \ -static struct subsys_attribute sys_##_prefix##_##_name##_attr = \ +static struct kobj_attribute sys_##_prefix##_##_name##_attr = \ __ATTR(_name,(S_IRUGO | S_IWUSR), \ sys_##_prefix##_##_name##_show, \ sys_##_prefix##_##_name##_store); #define DEFINE_IPL_ATTR_STR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)\ -static ssize_t sys_##_prefix##_##_name##_show(struct kset *kset, \ +static ssize_t sys_##_prefix##_##_name##_show(struct kobject *kobj, \ + struct kobj_attribute *attr, \ char *page) \ { \ return sprintf(page, _fmt_out, _value); \ } \ -static ssize_t sys_##_prefix##_##_name##_store(struct kset *kset, \ +static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj, \ + struct kobj_attribute *attr, \ const char *buf, size_t len) \ { \ if (sscanf(buf, _fmt_in, _value) != 1) \ return -EINVAL; \ return len; \ } \ -static struct subsys_attribute sys_##_prefix##_##_name##_attr = \ +static struct kobj_attribute sys_##_prefix##_##_name##_attr = \ __ATTR(_name,(S_IRUGO | S_IWUSR), \ sys_##_prefix##_##_name##_show, \ sys_##_prefix##_##_name##_store); @@ -270,14 +275,16 @@ void __init setup_ipl_info(void) struct ipl_info ipl_info; EXPORT_SYMBOL_GPL(ipl_info); -static ssize_t ipl_type_show(struct kset *kset, char *page) +static ssize_t ipl_type_show(struct kobject *kobj, struct kobj_attribute *attr, + char *page) { return sprintf(page, "%s\n", ipl_type_str(ipl_info.type)); } -static struct subsys_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type); +static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type); -static ssize_t sys_ipl_device_show(struct kset *kset, char *page) +static ssize_t sys_ipl_device_show(struct kobject *kobj, + struct kobj_attribute *attr, char *page) { struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START; @@ -292,7 +299,7 @@ static ssize_t sys_ipl_device_show(struct kset *kset, char *page) } } -static struct subsys_attribute sys_ipl_device_attr = +static struct kobj_attribute sys_ipl_device_attr = __ATTR(device, S_IRUGO, sys_ipl_device_show, NULL); static ssize_t ipl_parameter_read(struct kobject *kobj, struct bin_attribute *attr, @@ -367,7 +374,8 @@ static struct attribute_group ipl_fcp_attr_group = { /* CCW ipl device attributes */ -static ssize_t ipl_ccw_loadparm_show(struct kset *kset, char *page) +static ssize_t ipl_ccw_loadparm_show(struct kobject *kobj, + struct kobj_attribute *attr, char *page) { char loadparm[LOADPARM_LEN + 1] = {}; @@ -379,7 +387,7 @@ static ssize_t ipl_ccw_loadparm_show(struct kset *kset, char *page) return sprintf(page, "%s\n", loadparm); } -static struct subsys_attribute sys_ipl_ccw_loadparm_attr = +static struct kobj_attribute sys_ipl_ccw_loadparm_attr = __ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL); static struct attribute *ipl_ccw_attrs[] = { @@ -418,7 +426,7 @@ static struct attribute_group ipl_unknown_attr_group = { .attrs = ipl_unknown_attrs, }; -static decl_subsys(ipl, NULL, NULL); +static struct kset *ipl_kset; /* * reipl section @@ -465,7 +473,8 @@ static void reipl_get_ascii_loadparm(char *loadparm) strstrip(loadparm); } -static ssize_t reipl_ccw_loadparm_show(struct kset *kset, char *page) +static ssize_t reipl_ccw_loadparm_show(struct kobject *kobj, + struct kobj_attribute *attr, char *page) { char buf[LOADPARM_LEN + 1]; @@ -473,7 +482,8 @@ static ssize_t reipl_ccw_loadparm_show(struct kset *kset, char *page) return sprintf(page, "%s\n", buf); } -static ssize_t reipl_ccw_loadparm_store(struct kset *kset, +static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t len) { int i, lp_len; @@ -500,7 +510,7 @@ static ssize_t reipl_ccw_loadparm_store(struct kset *kset, return len; } -static struct subsys_attribute sys_reipl_ccw_loadparm_attr = +static struct kobj_attribute sys_reipl_ccw_loadparm_attr = __ATTR(loadparm, 0644, reipl_ccw_loadparm_show, reipl_ccw_loadparm_store); @@ -568,13 +578,15 @@ static int reipl_set_type(enum ipl_type type) return 0; } -static ssize_t reipl_type_show(struct kset *kset, char *page) +static ssize_t reipl_type_show(struct kobject *kobj, + struct kobj_attribute *attr, char *page) { return sprintf(page, "%s\n", ipl_type_str(reipl_type)); } -static ssize_t reipl_type_store(struct kset *kset, const char *buf, - size_t len) +static ssize_t reipl_type_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t len) { int rc = -EINVAL; @@ -587,10 +599,10 @@ static ssize_t reipl_type_store(struct kset *kset, const char *buf, return (rc != 0) ? rc : len; } -static struct subsys_attribute reipl_type_attr = +static struct kobj_attribute reipl_type_attr = __ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store); -static decl_subsys(reipl, NULL, NULL); +static struct kset *reipl_kset; /* * dump section @@ -663,13 +675,15 @@ static int dump_set_type(enum dump_type type) return 0; } -static ssize_t dump_type_show(struct kset *kset, char *page) +static ssize_t dump_type_show(struct kobject *kobj, + struct kobj_attribute *attr, char *page) { return sprintf(page, "%s\n", dump_type_str(dump_type)); } -static ssize_t dump_type_store(struct kset *kset, const char *buf, - size_t len) +static ssize_t dump_type_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t len) { int rc = -EINVAL; @@ -682,26 +696,28 @@ static ssize_t dump_type_store(struct kset *kset, const char *buf, return (rc != 0) ? rc : len; } -static struct subsys_attribute dump_type_attr = +static struct kobj_attribute dump_type_attr = __ATTR(dump_type, 0644, dump_type_show, dump_type_store); -static decl_subsys(dump, NULL, NULL); +static struct kset *dump_kset; /* * Shutdown actions section */ -static decl_subsys(shutdown_actions, NULL, NULL); +static struct kset *shutdown_actions_kset; /* on panic */ -static ssize_t on_panic_show(struct kset *kset, char *page) +static ssize_t on_panic_show(struct kobject *kobj, + struct kobj_attribute *attr, char *page) { return sprintf(page, "%s\n", shutdown_action_str(on_panic_action)); } -static ssize_t on_panic_store(struct kset *kset, const char *buf, - size_t len) +static ssize_t on_panic_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t len) { if (strncmp(buf, SHUTDOWN_REIPL_STR, strlen(SHUTDOWN_REIPL_STR)) == 0) on_panic_action = SHUTDOWN_REIPL; @@ -717,7 +733,7 @@ static ssize_t on_panic_store(struct kset *kset, const char *buf, return len; } -static struct subsys_attribute on_panic_attr = +static struct kobj_attribute on_panic_attr = __ATTR(on_panic, 0644, on_panic_show, on_panic_store); void do_reipl(void) @@ -814,23 +830,23 @@ static int __init ipl_register_fcp_files(void) { int rc; - rc = sysfs_create_group(&ipl_subsys.kobj, + rc = sysfs_create_group(&ipl_kset->kobj, &ipl_fcp_attr_group); if (rc) goto out; - rc = sysfs_create_bin_file(&ipl_subsys.kobj, + rc = sysfs_create_bin_file(&ipl_kset->kobj, &ipl_parameter_attr); if (rc) goto out_ipl_parm; - rc = sysfs_create_bin_file(&ipl_subsys.kobj, + rc = sysfs_create_bin_file(&ipl_kset->kobj, &ipl_scp_data_attr); if (!rc) goto out; - sysfs_remove_bin_file(&ipl_subsys.kobj, &ipl_parameter_attr); + sysfs_remove_bin_file(&ipl_kset->kobj, &ipl_parameter_attr); out_ipl_parm: - sysfs_remove_group(&ipl_subsys.kobj, &ipl_fcp_attr_group); + sysfs_remove_group(&ipl_kset->kobj, &ipl_fcp_attr_group); out: return rc; } @@ -839,12 +855,12 @@ static int __init ipl_init(void) { int rc; - rc = firmware_register(&ipl_subsys); - if (rc) - return rc; + ipl_kset = kset_create_and_add("ipl", NULL, firmware_kobj); + if (!ipl_kset) + return -ENOMEM; switch (ipl_info.type) { case IPL_TYPE_CCW: - rc = sysfs_create_group(&ipl_subsys.kobj, + rc = sysfs_create_group(&ipl_kset->kobj, &ipl_ccw_attr_group); break; case IPL_TYPE_FCP: @@ -852,16 +868,16 @@ static int __init ipl_init(void) rc = ipl_register_fcp_files(); break; case IPL_TYPE_NSS: - rc = sysfs_create_group(&ipl_subsys.kobj, + rc = sysfs_create_group(&ipl_kset->kobj, &ipl_nss_attr_group); break; default: - rc = sysfs_create_group(&ipl_subsys.kobj, + rc = sysfs_create_group(&ipl_kset->kobj, &ipl_unknown_attr_group); break; } if (rc) - firmware_unregister(&ipl_subsys); + kset_unregister(ipl_kset); return rc; } @@ -883,7 +899,7 @@ static int __init reipl_nss_init(void) if (!MACHINE_IS_VM) return 0; - rc = sysfs_create_group(&reipl_subsys.kobj, &reipl_nss_attr_group); + rc = sysfs_create_group(&reipl_kset->kobj, &reipl_nss_attr_group); if (rc) return rc; strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1); @@ -898,7 +914,7 @@ static int __init reipl_ccw_init(void) reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL); if (!reipl_block_ccw) return -ENOMEM; - rc = sysfs_create_group(&reipl_subsys.kobj, &reipl_ccw_attr_group); + rc = sysfs_create_group(&reipl_kset->kobj, &reipl_ccw_attr_group); if (rc) { free_page((unsigned long)reipl_block_ccw); return rc; @@ -936,7 +952,7 @@ static int __init reipl_fcp_init(void) reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL); if (!reipl_block_fcp) return -ENOMEM; - rc = sysfs_create_group(&reipl_subsys.kobj, &reipl_fcp_attr_group); + rc = sysfs_create_group(&reipl_kset->kobj, &reipl_fcp_attr_group); if (rc) { free_page((unsigned long)reipl_block_fcp); return rc; @@ -958,12 +974,12 @@ static int __init reipl_init(void) { int rc; - rc = firmware_register(&reipl_subsys); - if (rc) - return rc; - rc = subsys_create_file(&reipl_subsys, &reipl_type_attr); + reipl_kset = kset_create_and_add("reipl", NULL, firmware_kobj); + if (!reipl_kset) + return -ENOMEM; + rc = sysfs_create_file(&reipl_kset->kobj, &reipl_type_attr.attr); if (rc) { - firmware_unregister(&reipl_subsys); + kset_unregister(reipl_kset); return rc; } rc = reipl_ccw_init(); @@ -988,7 +1004,7 @@ static int __init dump_ccw_init(void) dump_block_ccw = (void *) get_zeroed_page(GFP_KERNEL); if (!dump_block_ccw) return -ENOMEM; - rc = sysfs_create_group(&dump_subsys.kobj, &dump_ccw_attr_group); + rc = sysfs_create_group(&dump_kset->kobj, &dump_ccw_attr_group); if (rc) { free_page((unsigned long)dump_block_ccw); return rc; @@ -1012,7 +1028,7 @@ static int __init dump_fcp_init(void) dump_block_fcp = (void *) get_zeroed_page(GFP_KERNEL); if (!dump_block_fcp) return -ENOMEM; - rc = sysfs_create_group(&dump_subsys.kobj, &dump_fcp_attr_group); + rc = sysfs_create_group(&dump_kset->kobj, &dump_fcp_attr_group); if (rc) { free_page((unsigned long)dump_block_fcp); return rc; @@ -1047,12 +1063,12 @@ static int __init dump_init(void) { int rc; - rc = firmware_register(&dump_subsys); - if (rc) - return rc; - rc = subsys_create_file(&dump_subsys, &dump_type_attr); + dump_kset = kset_create_and_add("dump", NULL, firmware_kobj); + if (!dump_kset) + return -ENOMEM; + rc = sysfs_create_file(&dump_kset->kobj, &dump_type_attr); if (rc) { - firmware_unregister(&dump_subsys); + kset_unregister(dump_kset); return rc; } rc = dump_ccw_init(); @@ -1069,12 +1085,13 @@ static int __init shutdown_actions_init(void) { int rc; - rc = firmware_register(&shutdown_actions_subsys); - if (rc) - return rc; - rc = subsys_create_file(&shutdown_actions_subsys, &on_panic_attr); + shutdown_actions_kset = kset_create_and_add("shutdown_actions", NULL, + firmware_kobj); + if (!shutdown_actions_kset) + return -ENOMEM; + rc = sysfs_create_file(&shutdown_actions_kset->kobj, &on_panic_attr); if (rc) { - firmware_unregister(&shutdown_actions_subsys); + kset_unregister(shutdown_actions_kset); return rc; } atomic_notifier_chain_register(&panic_notifier_list, diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 22b800ce2126d0fed3c47400229ef95f4060310b..3bbac1293be45d020ffbb703f74c8c8272ff70ad 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -1145,7 +1145,7 @@ static void etr_work_fn(struct work_struct *work) * Sysfs interface functions */ static struct sysdev_class etr_sysclass = { - set_kset_name("etr") + .name = "etr", }; static struct sys_device etr_port0_dev = { diff --git a/arch/sh/drivers/dma/dma-sysfs.c b/arch/sh/drivers/dma/dma-sysfs.c index eebcd4768bbf01a12ecbfd2cd6b06b0e60f3c5d8..51b57c0d1a3c01f98d99e4bb5071cdb1478b89d3 100644 --- a/arch/sh/drivers/dma/dma-sysfs.c +++ b/arch/sh/drivers/dma/dma-sysfs.c @@ -19,7 +19,7 @@ #include <asm/dma.h> static struct sysdev_class dma_sysclass = { - set_kset_name("dma"), + .name = "dma", }; EXPORT_SYMBOL(dma_sysclass); diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c index b22a78c807e6bb012ba2f4289673176c598e8453..3008c00eea6b6c269e7fa6bde3e2e43ca4d0f4b8 100644 --- a/arch/sh/kernel/cpu/sh4/sq.c +++ b/arch/sh/kernel/cpu/sh4/sq.c @@ -341,17 +341,18 @@ static int __devinit sq_sysdev_add(struct sys_device *sysdev) { unsigned int cpu = sysdev->id; struct kobject *kobj; + int error; sq_kobject[cpu] = kzalloc(sizeof(struct kobject), GFP_KERNEL); if (unlikely(!sq_kobject[cpu])) return -ENOMEM; kobj = sq_kobject[cpu]; - kobj->parent = &sysdev->kobj; - kobject_set_name(kobj, "%s", "sq"); - kobj->ktype = &ktype_percpu_entry; - - return kobject_register(kobj); + error = kobject_init_and_add(kobj, &ktype_percpu_entry, &sysdev->kobj, + "%s", "sq"); + if (!error) + kobject_uevent(kobj, KOBJ_ADD); + return error; } static int __devexit sq_sysdev_remove(struct sys_device *sysdev) @@ -359,7 +360,7 @@ static int __devexit sq_sysdev_remove(struct sys_device *sysdev) unsigned int cpu = sysdev->id; struct kobject *kobj = sq_kobject[cpu]; - kobject_unregister(kobj); + kobject_put(kobj); return 0; } diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c index a3a67d151e520285b08c7fd58cc93d618e079fe6..2bc04bfee73891045e92df6506287aa5ce1e102b 100644 --- a/arch/sh/kernel/time.c +++ b/arch/sh/kernel/time.c @@ -174,7 +174,7 @@ int timer_resume(struct sys_device *dev) #endif static struct sysdev_class timer_sysclass = { - set_kset_name("timer"), + .name = "timer", .suspend = timer_suspend, .resume = timer_resume, }; diff --git a/arch/x86/kernel/apic_32.c b/arch/x86/kernel/apic_32.c index edb5108e5d0e057f24dabe50ae1fde323b9fed56..a56c782653be7dc17474e133518d75f299659945 100644 --- a/arch/x86/kernel/apic_32.c +++ b/arch/x86/kernel/apic_32.c @@ -1530,7 +1530,7 @@ static int lapic_resume(struct sys_device *dev) */ static struct sysdev_class lapic_sysclass = { - set_kset_name("lapic"), + .name = "lapic", .resume = lapic_resume, .suspend = lapic_suspend, }; diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c index f28ccb588fbab8996cd76512d2c1bae24e4b1a2c..fa6cdee6d303a9dbd29b9f198fd2742140ebc0d8 100644 --- a/arch/x86/kernel/apic_64.c +++ b/arch/x86/kernel/apic_64.c @@ -639,7 +639,7 @@ static int lapic_resume(struct sys_device *dev) } static struct sysdev_class lapic_sysclass = { - set_kset_name("lapic"), + .name = "lapic", .resume = lapic_resume, .suspend = lapic_suspend, }; diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c index 9f530ff43c213ec3def93623fe36c11658721734..8b4507b8469b18ed09f906e35b94ba6649e75b8a 100644 --- a/arch/x86/kernel/cpu/intel_cacheinfo.c +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c @@ -733,10 +733,8 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev) if (unlikely(retval < 0)) return retval; - cache_kobject[cpu]->parent = &sys_dev->kobj; - kobject_set_name(cache_kobject[cpu], "%s", "cache"); - cache_kobject[cpu]->ktype = &ktype_percpu_entry; - retval = kobject_register(cache_kobject[cpu]); + retval = kobject_init_and_add(cache_kobject[cpu], &ktype_percpu_entry, + &sys_dev->kobj, "%s", "cache"); if (retval < 0) { cpuid4_cache_sysfs_exit(cpu); return retval; @@ -746,23 +744,23 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev) this_object = INDEX_KOBJECT_PTR(cpu,i); this_object->cpu = cpu; this_object->index = i; - this_object->kobj.parent = cache_kobject[cpu]; - kobject_set_name(&(this_object->kobj), "index%1lu", i); - this_object->kobj.ktype = &ktype_cache; - retval = kobject_register(&(this_object->kobj)); + retval = kobject_init_and_add(&(this_object->kobj), + &ktype_cache, cache_kobject[cpu], + "index%1lu", i); if (unlikely(retval)) { for (j = 0; j < i; j++) { - kobject_unregister( - &(INDEX_KOBJECT_PTR(cpu,j)->kobj)); + kobject_put(&(INDEX_KOBJECT_PTR(cpu,j)->kobj)); } - kobject_unregister(cache_kobject[cpu]); + kobject_put(cache_kobject[cpu]); cpuid4_cache_sysfs_exit(cpu); break; } + kobject_uevent(&(this_object->kobj), KOBJ_ADD); } if (!retval) cpu_set(cpu, cache_dev_map); + kobject_uevent(cache_kobject[cpu], KOBJ_ADD); return retval; } @@ -778,8 +776,8 @@ static void __cpuinit cache_remove_dev(struct sys_device * sys_dev) cpu_clear(cpu, cache_dev_map); for (i = 0; i < num_cache_leaves; i++) - kobject_unregister(&(INDEX_KOBJECT_PTR(cpu,i)->kobj)); - kobject_unregister(cache_kobject[cpu]); + kobject_put(&(INDEX_KOBJECT_PTR(cpu,i)->kobj)); + kobject_put(cache_kobject[cpu]); cpuid4_cache_sysfs_exit(cpu); } diff --git a/arch/x86/kernel/cpu/mcheck/mce_64.c b/arch/x86/kernel/cpu/mcheck/mce_64.c index 4b21d29fb5aa575b6146132db6dadd319ac5ca4a..242e8668dbeb2a6904b9b15feee00f827e099d5f 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_64.c +++ b/arch/x86/kernel/cpu/mcheck/mce_64.c @@ -745,7 +745,7 @@ static void mce_restart(void) static struct sysdev_class mce_sysclass = { .resume = mce_resume, - set_kset_name("machinecheck"), + .name = "machinecheck", }; DEFINE_PER_CPU(struct sys_device, device_mce); diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd_64.c b/arch/x86/kernel/cpu/mcheck/mce_amd_64.c index 752fb16a817d7187ac1732e66c426a12a19ff352..753588755feeb6d76d079cefe64d39236438a86e 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd_64.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd_64.c @@ -65,7 +65,7 @@ static struct threshold_block threshold_defaults = { }; struct threshold_bank { - struct kobject kobj; + struct kobject *kobj; struct threshold_block *blocks; cpumask_t cpus; }; @@ -432,10 +432,9 @@ static __cpuinit int allocate_threshold_blocks(unsigned int cpu, else per_cpu(threshold_banks, cpu)[bank]->blocks = b; - kobject_set_name(&b->kobj, "misc%i", block); - b->kobj.parent = &per_cpu(threshold_banks, cpu)[bank]->kobj; - b->kobj.ktype = &threshold_ktype; - err = kobject_register(&b->kobj); + err = kobject_init_and_add(&b->kobj, &threshold_ktype, + per_cpu(threshold_banks, cpu)[bank]->kobj, + "misc%i", block); if (err) goto out_free; recurse: @@ -451,11 +450,13 @@ static __cpuinit int allocate_threshold_blocks(unsigned int cpu, if (err) goto out_free; + kobject_uevent(&b->kobj, KOBJ_ADD); + return err; out_free: if (b) { - kobject_unregister(&b->kobj); + kobject_put(&b->kobj); kfree(b); } return err; @@ -489,7 +490,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank) goto out; err = sysfs_create_link(&per_cpu(device_mce, cpu).kobj, - &b->kobj, name); + b->kobj, name); if (err) goto out; @@ -505,16 +506,15 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank) goto out; } - kobject_set_name(&b->kobj, "threshold_bank%i", bank); - b->kobj.parent = &per_cpu(device_mce, cpu).kobj; + b->kobj = kobject_create_and_add(name, &per_cpu(device_mce, cpu).kobj); + if (!b->kobj) + goto out_free; + #ifndef CONFIG_SMP b->cpus = CPU_MASK_ALL; #else b->cpus = per_cpu(cpu_core_map, cpu); #endif - err = kobject_register(&b->kobj); - if (err) - goto out_free; per_cpu(threshold_banks, cpu)[bank] = b; @@ -531,7 +531,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank) continue; err = sysfs_create_link(&per_cpu(device_mce, i).kobj, - &b->kobj, name); + b->kobj, name); if (err) goto out; @@ -581,7 +581,7 @@ static void deallocate_threshold_block(unsigned int cpu, return; list_for_each_entry_safe(pos, tmp, &head->blocks->miscj, miscj) { - kobject_unregister(&pos->kobj); + kobject_put(&pos->kobj); list_del(&pos->miscj); kfree(pos); } @@ -627,7 +627,7 @@ static void threshold_remove_bank(unsigned int cpu, int bank) deallocate_threshold_block(cpu, bank); free_out: - kobject_unregister(&b->kobj); + kobject_put(b->kobj); kfree(b); per_cpu(threshold_banks, cpu)[bank] = NULL; } diff --git a/arch/x86/kernel/cpuid.c b/arch/x86/kernel/cpuid.c index 05c9936a16ccc50c015dae4c3af81552d4564fa7..d387c770c518e179413f4d2f891cbb86403ce45b 100644 --- a/arch/x86/kernel/cpuid.c +++ b/arch/x86/kernel/cpuid.c @@ -157,15 +157,15 @@ static int __cpuinit cpuid_class_cpu_callback(struct notifier_block *nfb, switch (action) { case CPU_UP_PREPARE: - case CPU_UP_PREPARE_FROZEN: err = cpuid_device_create(cpu); break; case CPU_UP_CANCELED: - case CPU_UP_CANCELED_FROZEN: case CPU_DEAD: - case CPU_DEAD_FROZEN: cpuid_device_destroy(cpu); break; + case CPU_UP_CANCELED_FROZEN: + destroy_suspended_device(cpuid_class, MKDEV(CPUID_MAJOR, cpu)); + break; } return err ? NOTIFY_BAD : NOTIFY_OK; } diff --git a/arch/x86/kernel/i8237.c b/arch/x86/kernel/i8237.c index 29313832df0c082409641e1e06f234320d72b254..dbd6c1d1b638bcd739747e54eac08f639d304242 100644 --- a/arch/x86/kernel/i8237.c +++ b/arch/x86/kernel/i8237.c @@ -51,7 +51,7 @@ static int i8237A_suspend(struct sys_device *dev, pm_message_t state) } static struct sysdev_class i8237_sysdev_class = { - set_kset_name("i8237"), + .name = "i8237", .suspend = i8237A_suspend, .resume = i8237A_resume, }; diff --git a/arch/x86/kernel/i8259_32.c b/arch/x86/kernel/i8259_32.c index f634fc715c99b455d3973645d4d16c3a80e13361..5f3496d0198403023f652a2e4d0a8a21816887ea 100644 --- a/arch/x86/kernel/i8259_32.c +++ b/arch/x86/kernel/i8259_32.c @@ -258,7 +258,7 @@ static int i8259A_shutdown(struct sys_device *dev) } static struct sysdev_class i8259_sysdev_class = { - set_kset_name("i8259"), + .name = "i8259", .suspend = i8259A_suspend, .resume = i8259A_resume, .shutdown = i8259A_shutdown, diff --git a/arch/x86/kernel/i8259_64.c b/arch/x86/kernel/i8259_64.c index 3f27ea0b9816fddb9a98d2587fd5c235b1e123ca..ba6d57286f5648ff299d10e9a2dcb88d0c563ceb 100644 --- a/arch/x86/kernel/i8259_64.c +++ b/arch/x86/kernel/i8259_64.c @@ -370,7 +370,7 @@ static int i8259A_shutdown(struct sys_device *dev) } static struct sysdev_class i8259_sysdev_class = { - set_kset_name("i8259"), + .name = "i8259", .suspend = i8259A_suspend, .resume = i8259A_resume, .shutdown = i8259A_shutdown, diff --git a/arch/x86/kernel/io_apic_32.c b/arch/x86/kernel/io_apic_32.c index a6b1490e00c4abac2953d106691bceec13954930..ab77f1905469592b724ce9c6bdd7c3ea70f0e408 100644 --- a/arch/x86/kernel/io_apic_32.c +++ b/arch/x86/kernel/io_apic_32.c @@ -2401,7 +2401,7 @@ static int ioapic_resume(struct sys_device *dev) } static struct sysdev_class ioapic_sysdev_class = { - set_kset_name("ioapic"), + .name = "ioapic", .suspend = ioapic_suspend, .resume = ioapic_resume, }; diff --git a/arch/x86/kernel/io_apic_64.c b/arch/x86/kernel/io_apic_64.c index cbac1670c7c36ec4ee8c268618b4a8014859c2f3..23a3ac06a23ea1dc68d6d79f6cf7eb3f9f215f96 100644 --- a/arch/x86/kernel/io_apic_64.c +++ b/arch/x86/kernel/io_apic_64.c @@ -1850,7 +1850,7 @@ static int ioapic_resume(struct sys_device *dev) } static struct sysdev_class ioapic_sysdev_class = { - set_kset_name("ioapic"), + .name = "ioapic", .suspend = ioapic_suspend, .resume = ioapic_resume, }; diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c index ee6eba4ecfeaadee33e8875be5a4f3b1ccd253d0..21f6e3c0be185c657d307042168fef4509073798 100644 --- a/arch/x86/kernel/msr.c +++ b/arch/x86/kernel/msr.c @@ -155,15 +155,15 @@ static int __cpuinit msr_class_cpu_callback(struct notifier_block *nfb, switch (action) { case CPU_UP_PREPARE: - case CPU_UP_PREPARE_FROZEN: err = msr_device_create(cpu); break; case CPU_UP_CANCELED: - case CPU_UP_CANCELED_FROZEN: case CPU_DEAD: - case CPU_DEAD_FROZEN: msr_device_destroy(cpu); break; + case CPU_UP_CANCELED_FROZEN: + destroy_suspended_device(msr_class, MKDEV(MSR_MAJOR, cpu)); + break; } return err ? NOTIFY_BAD : NOTIFY_OK; } diff --git a/arch/x86/kernel/nmi_32.c b/arch/x86/kernel/nmi_32.c index 852db290692186d3f2697e6982a1d77494e708be..4f4bfd3a88b6f89bb6bf080bb1e69787e320f2e7 100644 --- a/arch/x86/kernel/nmi_32.c +++ b/arch/x86/kernel/nmi_32.c @@ -176,7 +176,7 @@ static int lapic_nmi_resume(struct sys_device *dev) static struct sysdev_class nmi_sysclass = { - set_kset_name("lapic_nmi"), + .name = "lapic_nmi", .resume = lapic_nmi_resume, .suspend = lapic_nmi_suspend, }; diff --git a/arch/x86/kernel/nmi_64.c b/arch/x86/kernel/nmi_64.c index 4253c4e8849cd3abb29c519dc2d4d36d6b6627c3..c3d1476b6a1170673b6ab03a991c320f70af8ec8 100644 --- a/arch/x86/kernel/nmi_64.c +++ b/arch/x86/kernel/nmi_64.c @@ -211,7 +211,7 @@ static int lapic_nmi_resume(struct sys_device *dev) } static struct sysdev_class nmi_sysclass = { - set_kset_name("lapic_nmi"), + .name = "lapic_nmi", .resume = lapic_nmi_resume, .suspend = lapic_nmi_suspend, }; diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 944bbcdd2b8d47035c4202c3331c44d19fdae787..c8ab79ef42761f1df1cfffc2b53a205e5a5282ce 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -51,7 +51,7 @@ static int nmi_resume(struct sys_device *dev) static struct sysdev_class oprofile_sysclass = { - set_kset_name("oprofile"), + .name = "oprofile", .resume = nmi_resume, .suspend = nmi_suspend, }; diff --git a/block/elevator.c b/block/elevator.c index e452deb803957c1f71d71901ef669a630036363b..f9736fbdab0308f7121694df2faa3ffa68258994 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -185,9 +185,7 @@ static elevator_t *elevator_alloc(struct request_queue *q, eq->ops = &e->ops; eq->elevator_type = e; - kobject_init(&eq->kobj); - kobject_set_name(&eq->kobj, "%s", "iosched"); - eq->kobj.ktype = &elv_ktype; + kobject_init(&eq->kobj, &elv_ktype); mutex_init(&eq->sysfs_lock); eq->hash = kmalloc_node(sizeof(struct hlist_head) * ELV_HASH_ENTRIES, @@ -931,9 +929,7 @@ int elv_register_queue(struct request_queue *q) elevator_t *e = q->elevator; int error; - e->kobj.parent = &q->kobj; - - error = kobject_add(&e->kobj); + error = kobject_add(&e->kobj, &q->kobj, "%s", "iosched"); if (!error) { struct elv_fs_entry *attr = e->elevator_type->elevator_attrs; if (attr) { diff --git a/block/genhd.c b/block/genhd.c index f2ac914160d1a96e7258bd86949caef3dcdec6a3..5e4ab4b37d9f4f94e05a8c741693cafd177d28f0 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -17,8 +17,10 @@ #include <linux/buffer_head.h> #include <linux/mutex.h> -struct kset block_subsys; -static DEFINE_MUTEX(block_subsys_lock); +static DEFINE_MUTEX(block_class_lock); +#ifndef CONFIG_SYSFS_DEPRECATED +struct kobject *block_depr; +#endif /* * Can be deleted altogether. Later. @@ -37,19 +39,17 @@ static inline int major_to_index(int major) } #ifdef CONFIG_PROC_FS - void blkdev_show(struct seq_file *f, off_t offset) { struct blk_major_name *dp; if (offset < BLKDEV_MAJOR_HASH_SIZE) { - mutex_lock(&block_subsys_lock); + mutex_lock(&block_class_lock); for (dp = major_names[offset]; dp; dp = dp->next) seq_printf(f, "%3d %s\n", dp->major, dp->name); - mutex_unlock(&block_subsys_lock); + mutex_unlock(&block_class_lock); } } - #endif /* CONFIG_PROC_FS */ int register_blkdev(unsigned int major, const char *name) @@ -57,7 +57,7 @@ int register_blkdev(unsigned int major, const char *name) struct blk_major_name **n, *p; int index, ret = 0; - mutex_lock(&block_subsys_lock); + mutex_lock(&block_class_lock); /* temporary */ if (major == 0) { @@ -102,7 +102,7 @@ int register_blkdev(unsigned int major, const char *name) kfree(p); } out: - mutex_unlock(&block_subsys_lock); + mutex_unlock(&block_class_lock); return ret; } @@ -114,7 +114,7 @@ void unregister_blkdev(unsigned int major, const char *name) struct blk_major_name *p = NULL; int index = major_to_index(major); - mutex_lock(&block_subsys_lock); + mutex_lock(&block_class_lock); for (n = &major_names[index]; *n; n = &(*n)->next) if ((*n)->major == major) break; @@ -124,7 +124,7 @@ void unregister_blkdev(unsigned int major, const char *name) p = *n; *n = p->next; } - mutex_unlock(&block_subsys_lock); + mutex_unlock(&block_class_lock); kfree(p); } @@ -137,29 +137,30 @@ static struct kobj_map *bdev_map; * range must be nonzero * The hash chain is sorted on range, so that subranges can override. */ -void blk_register_region(dev_t dev, unsigned long range, struct module *module, +void blk_register_region(dev_t devt, unsigned long range, struct module *module, struct kobject *(*probe)(dev_t, int *, void *), int (*lock)(dev_t, void *), void *data) { - kobj_map(bdev_map, dev, range, module, probe, lock, data); + kobj_map(bdev_map, devt, range, module, probe, lock, data); } EXPORT_SYMBOL(blk_register_region); -void blk_unregister_region(dev_t dev, unsigned long range) +void blk_unregister_region(dev_t devt, unsigned long range) { - kobj_unmap(bdev_map, dev, range); + kobj_unmap(bdev_map, devt, range); } EXPORT_SYMBOL(blk_unregister_region); -static struct kobject *exact_match(dev_t dev, int *part, void *data) +static struct kobject *exact_match(dev_t devt, int *part, void *data) { struct gendisk *p = data; - return &p->kobj; + + return &p->dev.kobj; } -static int exact_lock(dev_t dev, void *data) +static int exact_lock(dev_t devt, void *data) { struct gendisk *p = data; @@ -194,8 +195,6 @@ void unlink_gendisk(struct gendisk *disk) disk->minors); } -#define to_disk(obj) container_of(obj,struct gendisk,kobj) - /** * get_gendisk - get partitioning information for a given device * @dev: device to get partitioning information for @@ -203,10 +202,12 @@ void unlink_gendisk(struct gendisk *disk) * This function gets the structure containing partitioning * information for the given device @dev. */ -struct gendisk *get_gendisk(dev_t dev, int *part) +struct gendisk *get_gendisk(dev_t devt, int *part) { - struct kobject *kobj = kobj_lookup(bdev_map, dev, part); - return kobj ? to_disk(kobj) : NULL; + struct kobject *kobj = kobj_lookup(bdev_map, devt, part); + struct device *dev = kobj_to_dev(kobj); + + return kobj ? dev_to_disk(dev) : NULL; } /* @@ -216,13 +217,17 @@ struct gendisk *get_gendisk(dev_t dev, int *part) */ void __init printk_all_partitions(void) { - int n; + struct device *dev; struct gendisk *sgp; + char buf[BDEVNAME_SIZE]; + int n; - mutex_lock(&block_subsys_lock); + mutex_lock(&block_class_lock); /* For each block device... */ - list_for_each_entry(sgp, &block_subsys.list, kobj.entry) { - char buf[BDEVNAME_SIZE]; + list_for_each_entry(dev, &block_class.devices, node) { + if (dev->type != &disk_type) + continue; + sgp = dev_to_disk(dev); /* * Don't show empty devices or things that have been surpressed */ @@ -255,38 +260,46 @@ void __init printk_all_partitions(void) sgp->major, n + 1 + sgp->first_minor, (unsigned long long)sgp->part[n]->nr_sects >> 1, disk_name(sgp, n + 1, buf)); - } /* partition subloop */ - } /* Block device loop */ + } + } - mutex_unlock(&block_subsys_lock); - return; + mutex_unlock(&block_class_lock); } #ifdef CONFIG_PROC_FS /* iterator */ static void *part_start(struct seq_file *part, loff_t *pos) { - struct list_head *p; - loff_t l = *pos; + loff_t k = *pos; + struct device *dev; - mutex_lock(&block_subsys_lock); - list_for_each(p, &block_subsys.list) - if (!l--) - return list_entry(p, struct gendisk, kobj.entry); + mutex_lock(&block_class_lock); + list_for_each_entry(dev, &block_class.devices, node) { + if (dev->type != &disk_type) + continue; + if (!k--) + return dev_to_disk(dev); + } return NULL; } static void *part_next(struct seq_file *part, void *v, loff_t *pos) { - struct list_head *p = ((struct gendisk *)v)->kobj.entry.next; + struct gendisk *gp = v; + struct device *dev; ++*pos; - return p==&block_subsys.list ? NULL : - list_entry(p, struct gendisk, kobj.entry); + list_for_each_entry(dev, &gp->dev.node, node) { + if (&dev->node == &block_class.devices) + return NULL; + if (dev->type == &disk_type) + return dev_to_disk(dev); + } + return NULL; } static void part_stop(struct seq_file *part, void *v) { - mutex_unlock(&block_subsys_lock); + mutex_unlock(&block_class_lock); } static int show_partition(struct seq_file *part, void *v) @@ -295,7 +308,7 @@ static int show_partition(struct seq_file *part, void *v) int n; char buf[BDEVNAME_SIZE]; - if (&sgp->kobj.entry == block_subsys.list.next) + if (&sgp->dev.node == block_class.devices.next) seq_puts(part, "major minor #blocks name\n\n"); /* Don't show non-partitionable removeable devices or empty devices */ @@ -325,110 +338,81 @@ static int show_partition(struct seq_file *part, void *v) } struct seq_operations partitions_op = { - .start =part_start, - .next = part_next, - .stop = part_stop, - .show = show_partition + .start = part_start, + .next = part_next, + .stop = part_stop, + .show = show_partition }; #endif extern int blk_dev_init(void); -static struct kobject *base_probe(dev_t dev, int *part, void *data) +static struct kobject *base_probe(dev_t devt, int *part, void *data) { - if (request_module("block-major-%d-%d", MAJOR(dev), MINOR(dev)) > 0) + if (request_module("block-major-%d-%d", MAJOR(devt), MINOR(devt)) > 0) /* Make old-style 2.4 aliases work */ - request_module("block-major-%d", MAJOR(dev)); + request_module("block-major-%d", MAJOR(devt)); return NULL; } static int __init genhd_device_init(void) { - int err; - - bdev_map = kobj_map_init(base_probe, &block_subsys_lock); + class_register(&block_class); + bdev_map = kobj_map_init(base_probe, &block_class_lock); blk_dev_init(); - err = subsystem_register(&block_subsys); - if (err < 0) - printk(KERN_WARNING "%s: subsystem_register error: %d\n", - __FUNCTION__, err); - return err; + +#ifndef CONFIG_SYSFS_DEPRECATED + /* create top-level block dir */ + block_depr = kobject_create_and_add("block", NULL); +#endif + return 0; } subsys_initcall(genhd_device_init); - - -/* - * kobject & sysfs bindings for block devices - */ -static ssize_t disk_attr_show(struct kobject *kobj, struct attribute *attr, - char *page) +static ssize_t disk_range_show(struct device *dev, + struct device_attribute *attr, char *buf) { - struct gendisk *disk = to_disk(kobj); - struct disk_attribute *disk_attr = - container_of(attr,struct disk_attribute,attr); - ssize_t ret = -EIO; + struct gendisk *disk = dev_to_disk(dev); - if (disk_attr->show) - ret = disk_attr->show(disk,page); - return ret; + return sprintf(buf, "%d\n", disk->minors); } -static ssize_t disk_attr_store(struct kobject * kobj, struct attribute * attr, - const char *page, size_t count) +static ssize_t disk_removable_show(struct device *dev, + struct device_attribute *attr, char *buf) { - struct gendisk *disk = to_disk(kobj); - struct disk_attribute *disk_attr = - container_of(attr,struct disk_attribute,attr); - ssize_t ret = 0; + struct gendisk *disk = dev_to_disk(dev); - if (disk_attr->store) - ret = disk_attr->store(disk, page, count); - return ret; + return sprintf(buf, "%d\n", + (disk->flags & GENHD_FL_REMOVABLE ? 1 : 0)); } -static struct sysfs_ops disk_sysfs_ops = { - .show = &disk_attr_show, - .store = &disk_attr_store, -}; - -static ssize_t disk_uevent_store(struct gendisk * disk, - const char *buf, size_t count) -{ - kobject_uevent(&disk->kobj, KOBJ_ADD); - return count; -} -static ssize_t disk_dev_read(struct gendisk * disk, char *page) -{ - dev_t base = MKDEV(disk->major, disk->first_minor); - return print_dev_t(page, base); -} -static ssize_t disk_range_read(struct gendisk * disk, char *page) +static ssize_t disk_size_show(struct device *dev, + struct device_attribute *attr, char *buf) { - return sprintf(page, "%d\n", disk->minors); -} -static ssize_t disk_removable_read(struct gendisk * disk, char *page) -{ - return sprintf(page, "%d\n", - (disk->flags & GENHD_FL_REMOVABLE ? 1 : 0)); + struct gendisk *disk = dev_to_disk(dev); + return sprintf(buf, "%llu\n", (unsigned long long)get_capacity(disk)); } -static ssize_t disk_size_read(struct gendisk * disk, char *page) -{ - return sprintf(page, "%llu\n", (unsigned long long)get_capacity(disk)); -} -static ssize_t disk_capability_read(struct gendisk *disk, char *page) + +static ssize_t disk_capability_show(struct device *dev, + struct device_attribute *attr, char *buf) { - return sprintf(page, "%x\n", disk->flags); + struct gendisk *disk = dev_to_disk(dev); + + return sprintf(buf, "%x\n", disk->flags); } -static ssize_t disk_stats_read(struct gendisk * disk, char *page) + +static ssize_t disk_stat_show(struct device *dev, + struct device_attribute *attr, char *buf) { + struct gendisk *disk = dev_to_disk(dev); + preempt_disable(); disk_round_stats(disk); preempt_enable(); - return sprintf(page, + return sprintf(buf, "%8lu %8lu %8llu %8u " "%8lu %8lu %8llu %8u " "%8u %8u %8u" @@ -445,40 +429,21 @@ static ssize_t disk_stats_read(struct gendisk * disk, char *page) jiffies_to_msecs(disk_stat_read(disk, io_ticks)), jiffies_to_msecs(disk_stat_read(disk, time_in_queue))); } -static struct disk_attribute disk_attr_uevent = { - .attr = {.name = "uevent", .mode = S_IWUSR }, - .store = disk_uevent_store -}; -static struct disk_attribute disk_attr_dev = { - .attr = {.name = "dev", .mode = S_IRUGO }, - .show = disk_dev_read -}; -static struct disk_attribute disk_attr_range = { - .attr = {.name = "range", .mode = S_IRUGO }, - .show = disk_range_read -}; -static struct disk_attribute disk_attr_removable = { - .attr = {.name = "removable", .mode = S_IRUGO }, - .show = disk_removable_read -}; -static struct disk_attribute disk_attr_size = { - .attr = {.name = "size", .mode = S_IRUGO }, - .show = disk_size_read -}; -static struct disk_attribute disk_attr_capability = { - .attr = {.name = "capability", .mode = S_IRUGO }, - .show = disk_capability_read -}; -static struct disk_attribute disk_attr_stat = { - .attr = {.name = "stat", .mode = S_IRUGO }, - .show = disk_stats_read -}; #ifdef CONFIG_FAIL_MAKE_REQUEST +static ssize_t disk_fail_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct gendisk *disk = dev_to_disk(dev); + + return sprintf(buf, "%d\n", disk->flags & GENHD_FL_FAIL ? 1 : 0); +} -static ssize_t disk_fail_store(struct gendisk * disk, +static ssize_t disk_fail_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { + struct gendisk *disk = dev_to_disk(dev); int i; if (count > 0 && sscanf(buf, "%d", &i) > 0) { @@ -490,136 +455,100 @@ static ssize_t disk_fail_store(struct gendisk * disk, return count; } -static ssize_t disk_fail_read(struct gendisk * disk, char *page) -{ - return sprintf(page, "%d\n", disk->flags & GENHD_FL_FAIL ? 1 : 0); -} -static struct disk_attribute disk_attr_fail = { - .attr = {.name = "make-it-fail", .mode = S_IRUGO | S_IWUSR }, - .store = disk_fail_store, - .show = disk_fail_read -}; #endif -static struct attribute * default_attrs[] = { - &disk_attr_uevent.attr, - &disk_attr_dev.attr, - &disk_attr_range.attr, - &disk_attr_removable.attr, - &disk_attr_size.attr, - &disk_attr_stat.attr, - &disk_attr_capability.attr, +static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL); +static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL); +static DEVICE_ATTR(size, S_IRUGO, disk_size_show, NULL); +static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL); +static DEVICE_ATTR(stat, S_IRUGO, disk_stat_show, NULL); +#ifdef CONFIG_FAIL_MAKE_REQUEST +static struct device_attribute dev_attr_fail = + __ATTR(make-it-fail, S_IRUGO|S_IWUSR, disk_fail_show, disk_fail_store); +#endif + +static struct attribute *disk_attrs[] = { + &dev_attr_range.attr, + &dev_attr_removable.attr, + &dev_attr_size.attr, + &dev_attr_capability.attr, + &dev_attr_stat.attr, #ifdef CONFIG_FAIL_MAKE_REQUEST - &disk_attr_fail.attr, + &dev_attr_fail.attr, #endif - NULL, + NULL +}; + +static struct attribute_group disk_attr_group = { + .attrs = disk_attrs, }; -static void disk_release(struct kobject * kobj) +static struct attribute_group *disk_attr_groups[] = { + &disk_attr_group, + NULL +}; + +static void disk_release(struct device *dev) { - struct gendisk *disk = to_disk(kobj); + struct gendisk *disk = dev_to_disk(dev); + kfree(disk->random); kfree(disk->part); free_disk_stats(disk); kfree(disk); } - -static struct kobj_type ktype_block = { - .release = disk_release, - .sysfs_ops = &disk_sysfs_ops, - .default_attrs = default_attrs, +struct class block_class = { + .name = "block", }; -extern struct kobj_type ktype_part; - -static int block_uevent_filter(struct kset *kset, struct kobject *kobj) -{ - struct kobj_type *ktype = get_ktype(kobj); - - return ((ktype == &ktype_block) || (ktype == &ktype_part)); -} - -static int block_uevent(struct kset *kset, struct kobject *kobj, - struct kobj_uevent_env *env) -{ - struct kobj_type *ktype = get_ktype(kobj); - struct device *physdev; - struct gendisk *disk; - struct hd_struct *part; - - if (ktype == &ktype_block) { - disk = container_of(kobj, struct gendisk, kobj); - add_uevent_var(env, "MINOR=%u", disk->first_minor); - } else if (ktype == &ktype_part) { - disk = container_of(kobj->parent, struct gendisk, kobj); - part = container_of(kobj, struct hd_struct, kobj); - add_uevent_var(env, "MINOR=%u", - disk->first_minor + part->partno); - } else - return 0; - - add_uevent_var(env, "MAJOR=%u", disk->major); - - /* add physical device, backing this device */ - physdev = disk->driverfs_dev; - if (physdev) { - char *path = kobject_get_path(&physdev->kobj, GFP_KERNEL); - - add_uevent_var(env, "PHYSDEVPATH=%s", path); - kfree(path); - - if (physdev->bus) - add_uevent_var(env, "PHYSDEVBUS=%s", physdev->bus->name); - - if (physdev->driver) - add_uevent_var(env, physdev->driver->name); - } - - return 0; -} - -static struct kset_uevent_ops block_uevent_ops = { - .filter = block_uevent_filter, - .uevent = block_uevent, +struct device_type disk_type = { + .name = "disk", + .groups = disk_attr_groups, + .release = disk_release, }; -decl_subsys(block, &ktype_block, &block_uevent_ops); - /* * aggregate disk stat collector. Uses the same stats that the sysfs * entries do, above, but makes them available through one seq_file. - * Watching a few disks may be efficient through sysfs, but watching - * all of them will be more efficient through this interface. * * The output looks suspiciously like /proc/partitions with a bunch of * extra fields. */ -/* iterator */ static void *diskstats_start(struct seq_file *part, loff_t *pos) { loff_t k = *pos; - struct list_head *p; + struct device *dev; - mutex_lock(&block_subsys_lock); - list_for_each(p, &block_subsys.list) + mutex_lock(&block_class_lock); + list_for_each_entry(dev, &block_class.devices, node) { + if (dev->type != &disk_type) + continue; if (!k--) - return list_entry(p, struct gendisk, kobj.entry); + return dev_to_disk(dev); + } return NULL; } static void *diskstats_next(struct seq_file *part, void *v, loff_t *pos) { - struct list_head *p = ((struct gendisk *)v)->kobj.entry.next; + struct gendisk *gp = v; + struct device *dev; + ++*pos; - return p==&block_subsys.list ? NULL : - list_entry(p, struct gendisk, kobj.entry); + list_for_each_entry(dev, &gp->dev.node, node) { + if (&dev->node == &block_class.devices) + return NULL; + if (dev->type == &disk_type) + return dev_to_disk(dev); + } + return NULL; } static void diskstats_stop(struct seq_file *part, void *v) { - mutex_unlock(&block_subsys_lock); + mutex_unlock(&block_class_lock); } static int diskstats_show(struct seq_file *s, void *v) @@ -629,7 +558,7 @@ static int diskstats_show(struct seq_file *s, void *v) int n = 0; /* - if (&sgp->kobj.entry == block_subsys.kset.list.next) + if (&gp->dev.kobj.entry == block_class.devices.next) seq_puts(s, "major minor name" " rio rmerge rsect ruse wio wmerge " "wsect wuse running use aveq" @@ -683,7 +612,7 @@ static void media_change_notify_thread(struct work_struct *work) * set enviroment vars to indicate which event this is for * so that user space will know to go check the media status. */ - kobject_uevent_env(&gd->kobj, KOBJ_CHANGE, envp); + kobject_uevent_env(&gd->dev.kobj, KOBJ_CHANGE, envp); put_device(gd->driverfs_dev); } @@ -694,6 +623,25 @@ void genhd_media_change_notify(struct gendisk *disk) } EXPORT_SYMBOL_GPL(genhd_media_change_notify); +dev_t blk_lookup_devt(const char *name) +{ + struct device *dev; + dev_t devt = MKDEV(0, 0); + + mutex_lock(&block_class_lock); + list_for_each_entry(dev, &block_class.devices, node) { + if (strcmp(dev->bus_id, name) == 0) { + devt = dev->devt; + break; + } + } + mutex_unlock(&block_class_lock); + + return devt; +} + +EXPORT_SYMBOL(blk_lookup_devt); + struct gendisk *alloc_disk(int minors) { return alloc_disk_node(minors, -1); @@ -721,9 +669,10 @@ struct gendisk *alloc_disk_node(int minors, int node_id) } } disk->minors = minors; - kobj_set_kset_s(disk,block_subsys); - kobject_init(&disk->kobj); rand_initialize_disk(disk); + disk->dev.class = &block_class; + disk->dev.type = &disk_type; + device_initialize(&disk->dev); INIT_WORK(&disk->async_notify, media_change_notify_thread); } @@ -743,7 +692,7 @@ struct kobject *get_disk(struct gendisk *disk) owner = disk->fops->owner; if (owner && !try_module_get(owner)) return NULL; - kobj = kobject_get(&disk->kobj); + kobj = kobject_get(&disk->dev.kobj); if (kobj == NULL) { module_put(owner); return NULL; @@ -757,7 +706,7 @@ EXPORT_SYMBOL(get_disk); void put_disk(struct gendisk *disk) { if (disk) - kobject_put(&disk->kobj); + kobject_put(&disk->dev.kobj); } EXPORT_SYMBOL(put_disk); diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 8b919940b2abdb37119cd9927b6f45dbec66aa31..5ccec8aa964bc51b386cb3dfc925be5825e65e67 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -1862,9 +1862,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) init_timer(&q->unplug_timer); - kobject_set_name(&q->kobj, "%s", "queue"); - q->kobj.ktype = &queue_ktype; - kobject_init(&q->kobj); + kobject_init(&q->kobj, &queue_ktype); mutex_init(&q->sysfs_lock); @@ -4182,9 +4180,8 @@ int blk_register_queue(struct gendisk *disk) if (!q || !q->request_fn) return -ENXIO; - q->kobj.parent = kobject_get(&disk->kobj); - - ret = kobject_add(&q->kobj); + ret = kobject_add(&q->kobj, kobject_get(&disk->dev.kobj), + "%s", "queue"); if (ret < 0) return ret; @@ -4209,6 +4206,6 @@ void blk_unregister_queue(struct gendisk *disk) kobject_uevent(&q->kobj, KOBJ_REMOVE); kobject_del(&q->kobj); - kobject_put(&disk->kobj); + kobject_put(&disk->dev.kobj); } } diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index f4487c38d9f294893ebc460f5f05c27b3918b77d..1b4cf984b081d0f0a697d139d1df0c1d281fe31e 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -743,7 +743,7 @@ static int __init acpi_bus_init(void) return -ENODEV; } -decl_subsys(acpi, NULL, NULL); +struct kobject *acpi_kobj; static int __init acpi_init(void) { @@ -755,10 +755,11 @@ static int __init acpi_init(void) return -ENODEV; } - result = firmware_register(&acpi_subsys); - if (result < 0) - printk(KERN_WARNING "%s: firmware_register error: %d\n", - __FUNCTION__, result); + acpi_kobj = kobject_create_and_add("acpi", firmware_kobj); + if (!acpi_kobj) { + printk(KERN_WARNING "%s: kset create error\n", __FUNCTION__); + acpi_kobj = NULL; + } result = acpi_bus_init(); diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index c9f526e55392b1260fb6896772b0ba77ef2ace8a..5400ea173f6fdf0fe309658e2c4de0b13bdbd462 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -911,7 +911,7 @@ __setup("acpi_irq_balance", acpi_irq_balance_set); /* FIXME: we will remove this interface after all drivers call pci_disable_device */ static struct sysdev_class irqrouter_sysdev_class = { - set_kset_name("irqrouter"), + .name = "irqrouter", .resume = irqrouter_resume, }; diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c index edee2806e37bcec904e6640a90fb2423b981260c..5ffe0ea18967a82cf8a8ecb4fd64dd7362f125b6 100644 --- a/drivers/acpi/system.c +++ b/drivers/acpi/system.c @@ -58,7 +58,7 @@ module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444); FS Interface (/sys) -------------------------------------------------------------------------- */ static LIST_HEAD(acpi_table_attr_list); -static struct kobject tables_kobj; +static struct kobject *tables_kobj; struct acpi_table_attr { struct bin_attribute attr; @@ -135,11 +135,9 @@ static int acpi_system_sysfs_init(void) int table_index = 0; int result; - tables_kobj.parent = &acpi_subsys.kobj; - kobject_set_name(&tables_kobj, "tables"); - result = kobject_register(&tables_kobj); - if (result) - return result; + tables_kobj = kobject_create_and_add("tables", acpi_kobj); + if (!tables_kobj) + return -ENOMEM; do { result = acpi_get_table_by_index(table_index, &table_header); @@ -153,7 +151,7 @@ static int acpi_system_sysfs_init(void) acpi_table_attr_init(table_attr, table_header); result = - sysfs_create_bin_file(&tables_kobj, + sysfs_create_bin_file(tables_kobj, &table_attr->attr); if (result) { kfree(table_attr); @@ -163,6 +161,7 @@ static int acpi_system_sysfs_init(void) &acpi_table_attr_list); } } while (!result); + kobject_uevent(tables_kobj, KOBJ_ADD); return 0; } diff --git a/drivers/base/Makefile b/drivers/base/Makefile index b39ea3f59c9b77edc9ec636383bcc3f3f3225f4e..63e09c015ca02305e6bb475d3ba8ca78c5677e63 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -11,6 +11,9 @@ obj-$(CONFIG_FW_LOADER) += firmware_class.o obj-$(CONFIG_NUMA) += node.o obj-$(CONFIG_MEMORY_HOTPLUG_SPARSE) += memory.o obj-$(CONFIG_SMP) += topology.o +ifeq ($(CONFIG_SYSFS),y) +obj-$(CONFIG_MODULES) += module.o +endif obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o ifeq ($(CONFIG_DEBUG_DRIVER),y) diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c index 7370d7cf59888050d374d7a48a03185a06f0df7c..d4dfb97de3b006a20caaf705e33c0d78a80a82fe 100644 --- a/drivers/base/attribute_container.c +++ b/drivers/base/attribute_container.c @@ -61,7 +61,7 @@ attribute_container_classdev_to_container(struct class_device *classdev) } EXPORT_SYMBOL_GPL(attribute_container_classdev_to_container); -static struct list_head attribute_container_list; +static LIST_HEAD(attribute_container_list); static DEFINE_MUTEX(attribute_container_mutex); @@ -429,10 +429,3 @@ attribute_container_find_class_device(struct attribute_container *cont, return cdev; } EXPORT_SYMBOL_GPL(attribute_container_find_class_device); - -int __init -attribute_container_init(void) -{ - INIT_LIST_HEAD(&attribute_container_list); - return 0; -} diff --git a/drivers/base/base.h b/drivers/base/base.h index 10b2fb6c9ce68fdbae4a9a4822a298ead5c3732b..c0444146c09a880a51e1b514e9fe8710119a2f67 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -1,6 +1,42 @@ -/* initialisation functions */ +/** + * struct bus_type_private - structure to hold the private to the driver core portions of the bus_type structure. + * + * @subsys - the struct kset that defines this bus. This is the main kobject + * @drivers_kset - the list of drivers associated with this bus + * @devices_kset - the list of devices associated with this bus + * @klist_devices - the klist to iterate over the @devices_kset + * @klist_drivers - the klist to iterate over the @drivers_kset + * @bus_notifier - the bus notifier list for anything that cares about things + * on this bus. + * @bus - pointer back to the struct bus_type that this structure is associated + * with. + * + * This structure is the one that is the actual kobject allowing struct + * bus_type to be statically allocated safely. Nothing outside of the driver + * core should ever touch these fields. + */ +struct bus_type_private { + struct kset subsys; + struct kset *drivers_kset; + struct kset *devices_kset; + struct klist klist_devices; + struct klist klist_drivers; + struct blocking_notifier_head bus_notifier; + unsigned int drivers_autoprobe:1; + struct bus_type *bus; +}; + +struct driver_private { + struct kobject kobj; + struct klist klist_devices; + struct klist_node knode_bus; + struct module_kobject *mkobj; + struct device_driver *driver; +}; +#define to_driver(obj) container_of(obj, struct driver_private, kobj) +/* initialisation functions */ extern int devices_init(void); extern int buses_init(void); extern int classes_init(void); @@ -13,17 +49,16 @@ static inline int hypervisor_init(void) { return 0; } extern int platform_bus_init(void); extern int system_bus_init(void); extern int cpu_dev_init(void); -extern int attribute_container_init(void); -extern int bus_add_device(struct device * dev); -extern void bus_attach_device(struct device * dev); -extern void bus_remove_device(struct device * dev); +extern int bus_add_device(struct device *dev); +extern void bus_attach_device(struct device *dev); +extern void bus_remove_device(struct device *dev); -extern int bus_add_driver(struct device_driver *); -extern void bus_remove_driver(struct device_driver *); +extern int bus_add_driver(struct device_driver *drv); +extern void bus_remove_driver(struct device_driver *drv); -extern void driver_detach(struct device_driver * drv); -extern int driver_probe_device(struct device_driver *, struct device *); +extern void driver_detach(struct device_driver *drv); +extern int driver_probe_device(struct device_driver *drv, struct device *dev); extern void sysdev_shutdown(void); extern int sysdev_suspend(pm_message_t state); @@ -44,4 +79,13 @@ extern char *make_class_name(const char *name, struct kobject *kobj); extern int devres_release_all(struct device *dev); -extern struct kset devices_subsys; +extern struct kset *devices_kset; + +#if defined(CONFIG_MODULES) && defined(CONFIG_SYSFS) +extern void module_add_driver(struct module *mod, struct device_driver *drv); +extern void module_remove_driver(struct device_driver *drv); +#else +static inline void module_add_driver(struct module *mod, + struct device_driver *drv) { } +static inline void module_remove_driver(struct device_driver *drv) { } +#endif diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 9a19b071c573aaa7d6fc17cdaa1f86e4a1d38580..f484495b2ad1bd27d83fae5cc661349e9cbdb78c 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -3,6 +3,8 @@ * * Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs + * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de> + * Copyright (c) 2007 Novell Inc. * * This file is released under the GPLv2 * @@ -17,14 +19,13 @@ #include "power/power.h" #define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr) -#define to_bus(obj) container_of(obj, struct bus_type, subsys.kobj) +#define to_bus(obj) container_of(obj, struct bus_type_private, subsys.kobj) /* * sysfs bindings for drivers */ #define to_drv_attr(_attr) container_of(_attr, struct driver_attribute, attr) -#define to_driver(obj) container_of(obj, struct device_driver, kobj) static int __must_check bus_rescan_devices_helper(struct device *dev, @@ -32,37 +33,40 @@ static int __must_check bus_rescan_devices_helper(struct device *dev, static struct bus_type *bus_get(struct bus_type *bus) { - return bus ? container_of(kset_get(&bus->subsys), - struct bus_type, subsys) : NULL; + if (bus) { + kset_get(&bus->p->subsys); + return bus; + } + return NULL; } static void bus_put(struct bus_type *bus) { - kset_put(&bus->subsys); + if (bus) + kset_put(&bus->p->subsys); } -static ssize_t -drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) +static ssize_t drv_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) { - struct driver_attribute * drv_attr = to_drv_attr(attr); - struct device_driver * drv = to_driver(kobj); + struct driver_attribute *drv_attr = to_drv_attr(attr); + struct driver_private *drv_priv = to_driver(kobj); ssize_t ret = -EIO; if (drv_attr->show) - ret = drv_attr->show(drv, buf); + ret = drv_attr->show(drv_priv->driver, buf); return ret; } -static ssize_t -drv_attr_store(struct kobject * kobj, struct attribute * attr, - const char * buf, size_t count) +static ssize_t drv_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) { - struct driver_attribute * drv_attr = to_drv_attr(attr); - struct device_driver * drv = to_driver(kobj); + struct driver_attribute *drv_attr = to_drv_attr(attr); + struct driver_private *drv_priv = to_driver(kobj); ssize_t ret = -EIO; if (drv_attr->store) - ret = drv_attr->store(drv, buf, count); + ret = drv_attr->store(drv_priv->driver, buf, count); return ret; } @@ -71,22 +75,12 @@ static struct sysfs_ops driver_sysfs_ops = { .store = drv_attr_store, }; - -static void driver_release(struct kobject * kobj) +static void driver_release(struct kobject *kobj) { - /* - * Yes this is an empty release function, it is this way because struct - * device is always a static object, not a dynamic one. Yes, this is - * not nice and bad, but remember, drivers are code, reference counted - * by the module count, not a device, which is really data. And yes, - * in the future I do want to have all drivers be created dynamically, - * and am working toward that goal, but it will take a bit longer... - * - * But do not let this example give _anyone_ the idea that they can - * create a release function without any code in it at all, to do that - * is almost always wrong. If you have any questions about this, - * please send an email to <greg@kroah.com> - */ + struct driver_private *drv_priv = to_driver(kobj); + + pr_debug("driver: '%s': %s\n", kobject_name(kobj), __FUNCTION__); + kfree(drv_priv); } static struct kobj_type driver_ktype = { @@ -94,34 +88,30 @@ static struct kobj_type driver_ktype = { .release = driver_release, }; - /* * sysfs bindings for buses */ - - -static ssize_t -bus_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) +static ssize_t bus_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) { - struct bus_attribute * bus_attr = to_bus_attr(attr); - struct bus_type * bus = to_bus(kobj); + struct bus_attribute *bus_attr = to_bus_attr(attr); + struct bus_type_private *bus_priv = to_bus(kobj); ssize_t ret = 0; if (bus_attr->show) - ret = bus_attr->show(bus, buf); + ret = bus_attr->show(bus_priv->bus, buf); return ret; } -static ssize_t -bus_attr_store(struct kobject * kobj, struct attribute * attr, - const char * buf, size_t count) +static ssize_t bus_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) { - struct bus_attribute * bus_attr = to_bus_attr(attr); - struct bus_type * bus = to_bus(kobj); + struct bus_attribute *bus_attr = to_bus_attr(attr); + struct bus_type_private *bus_priv = to_bus(kobj); ssize_t ret = 0; if (bus_attr->store) - ret = bus_attr->store(bus, buf, count); + ret = bus_attr->store(bus_priv->bus, buf, count); return ret; } @@ -130,24 +120,26 @@ static struct sysfs_ops bus_sysfs_ops = { .store = bus_attr_store, }; -int bus_create_file(struct bus_type * bus, struct bus_attribute * attr) +int bus_create_file(struct bus_type *bus, struct bus_attribute *attr) { int error; if (bus_get(bus)) { - error = sysfs_create_file(&bus->subsys.kobj, &attr->attr); + error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr); bus_put(bus); } else error = -EINVAL; return error; } +EXPORT_SYMBOL_GPL(bus_create_file); -void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr) +void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr) { if (bus_get(bus)) { - sysfs_remove_file(&bus->subsys.kobj, &attr->attr); + sysfs_remove_file(&bus->p->subsys.kobj, &attr->attr); bus_put(bus); } } +EXPORT_SYMBOL_GPL(bus_remove_file); static struct kobj_type bus_ktype = { .sysfs_ops = &bus_sysfs_ops, @@ -166,7 +158,7 @@ static struct kset_uevent_ops bus_uevent_ops = { .filter = bus_uevent_filter, }; -static decl_subsys(bus, &bus_ktype, &bus_uevent_ops); +static struct kset *bus_kset; #ifdef CONFIG_HOTPLUG @@ -224,10 +216,13 @@ static ssize_t driver_bind(struct device_driver *drv, if (dev->parent) up(&dev->parent->sem); - if (err > 0) /* success */ + if (err > 0) { + /* success */ err = count; - else if (err == 0) /* driver didn't accept device */ + } else if (err == 0) { + /* driver didn't accept device */ err = -ENODEV; + } } put_device(dev); bus_put(bus); @@ -237,16 +232,16 @@ static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind); static ssize_t show_drivers_autoprobe(struct bus_type *bus, char *buf) { - return sprintf(buf, "%d\n", bus->drivers_autoprobe); + return sprintf(buf, "%d\n", bus->p->drivers_autoprobe); } static ssize_t store_drivers_autoprobe(struct bus_type *bus, const char *buf, size_t count) { if (buf[0] == '0') - bus->drivers_autoprobe = 0; + bus->p->drivers_autoprobe = 0; else - bus->drivers_autoprobe = 1; + bus->p->drivers_autoprobe = 1; return count; } @@ -264,49 +259,49 @@ static ssize_t store_drivers_probe(struct bus_type *bus, } #endif -static struct device * next_device(struct klist_iter * i) +static struct device *next_device(struct klist_iter *i) { - struct klist_node * n = klist_next(i); + struct klist_node *n = klist_next(i); return n ? container_of(n, struct device, knode_bus) : NULL; } /** - * bus_for_each_dev - device iterator. - * @bus: bus type. - * @start: device to start iterating from. - * @data: data for the callback. - * @fn: function to be called for each device. + * bus_for_each_dev - device iterator. + * @bus: bus type. + * @start: device to start iterating from. + * @data: data for the callback. + * @fn: function to be called for each device. * - * Iterate over @bus's list of devices, and call @fn for each, - * passing it @data. If @start is not NULL, we use that device to - * begin iterating from. + * Iterate over @bus's list of devices, and call @fn for each, + * passing it @data. If @start is not NULL, we use that device to + * begin iterating from. * - * We check the return of @fn each time. If it returns anything - * other than 0, we break out and return that value. + * We check the return of @fn each time. If it returns anything + * other than 0, we break out and return that value. * - * NOTE: The device that returns a non-zero value is not retained - * in any way, nor is its refcount incremented. If the caller needs - * to retain this data, it should do, and increment the reference - * count in the supplied callback. + * NOTE: The device that returns a non-zero value is not retained + * in any way, nor is its refcount incremented. If the caller needs + * to retain this data, it should do, and increment the reference + * count in the supplied callback. */ - -int bus_for_each_dev(struct bus_type * bus, struct device * start, - void * data, int (*fn)(struct device *, void *)) +int bus_for_each_dev(struct bus_type *bus, struct device *start, + void *data, int (*fn)(struct device *, void *)) { struct klist_iter i; - struct device * dev; + struct device *dev; int error = 0; if (!bus) return -EINVAL; - klist_iter_init_node(&bus->klist_devices, &i, + klist_iter_init_node(&bus->p->klist_devices, &i, (start ? &start->knode_bus : NULL)); while ((dev = next_device(&i)) && !error) error = fn(dev, data); klist_iter_exit(&i); return error; } +EXPORT_SYMBOL_GPL(bus_for_each_dev); /** * bus_find_device - device iterator for locating a particular device. @@ -323,9 +318,9 @@ int bus_for_each_dev(struct bus_type * bus, struct device * start, * if it does. If the callback returns non-zero, this function will * return to the caller and not iterate over any more devices. */ -struct device * bus_find_device(struct bus_type *bus, - struct device *start, void *data, - int (*match)(struct device *, void *)) +struct device *bus_find_device(struct bus_type *bus, + struct device *start, void *data, + int (*match)(struct device *dev, void *data)) { struct klist_iter i; struct device *dev; @@ -333,7 +328,7 @@ struct device * bus_find_device(struct bus_type *bus, if (!bus) return NULL; - klist_iter_init_node(&bus->klist_devices, &i, + klist_iter_init_node(&bus->p->klist_devices, &i, (start ? &start->knode_bus : NULL)); while ((dev = next_device(&i))) if (match(dev, data) && get_device(dev)) @@ -341,51 +336,57 @@ struct device * bus_find_device(struct bus_type *bus, klist_iter_exit(&i); return dev; } +EXPORT_SYMBOL_GPL(bus_find_device); - -static struct device_driver * next_driver(struct klist_iter * i) +static struct device_driver *next_driver(struct klist_iter *i) { - struct klist_node * n = klist_next(i); - return n ? container_of(n, struct device_driver, knode_bus) : NULL; + struct klist_node *n = klist_next(i); + struct driver_private *drv_priv; + + if (n) { + drv_priv = container_of(n, struct driver_private, knode_bus); + return drv_priv->driver; + } + return NULL; } /** - * bus_for_each_drv - driver iterator - * @bus: bus we're dealing with. - * @start: driver to start iterating on. - * @data: data to pass to the callback. - * @fn: function to call for each driver. + * bus_for_each_drv - driver iterator + * @bus: bus we're dealing with. + * @start: driver to start iterating on. + * @data: data to pass to the callback. + * @fn: function to call for each driver. * - * This is nearly identical to the device iterator above. - * We iterate over each driver that belongs to @bus, and call - * @fn for each. If @fn returns anything but 0, we break out - * and return it. If @start is not NULL, we use it as the head - * of the list. + * This is nearly identical to the device iterator above. + * We iterate over each driver that belongs to @bus, and call + * @fn for each. If @fn returns anything but 0, we break out + * and return it. If @start is not NULL, we use it as the head + * of the list. * - * NOTE: we don't return the driver that returns a non-zero - * value, nor do we leave the reference count incremented for that - * driver. If the caller needs to know that info, it must set it - * in the callback. It must also be sure to increment the refcount - * so it doesn't disappear before returning to the caller. + * NOTE: we don't return the driver that returns a non-zero + * value, nor do we leave the reference count incremented for that + * driver. If the caller needs to know that info, it must set it + * in the callback. It must also be sure to increment the refcount + * so it doesn't disappear before returning to the caller. */ - -int bus_for_each_drv(struct bus_type * bus, struct device_driver * start, - void * data, int (*fn)(struct device_driver *, void *)) +int bus_for_each_drv(struct bus_type *bus, struct device_driver *start, + void *data, int (*fn)(struct device_driver *, void *)) { struct klist_iter i; - struct device_driver * drv; + struct device_driver *drv; int error = 0; if (!bus) return -EINVAL; - klist_iter_init_node(&bus->klist_drivers, &i, - start ? &start->knode_bus : NULL); + klist_iter_init_node(&bus->p->klist_drivers, &i, + start ? &start->p->knode_bus : NULL); while ((drv = next_driver(&i)) && !error) error = fn(drv, data); klist_iter_exit(&i); return error; } +EXPORT_SYMBOL_GPL(bus_for_each_drv); static int device_add_attrs(struct bus_type *bus, struct device *dev) { @@ -396,7 +397,7 @@ static int device_add_attrs(struct bus_type *bus, struct device *dev) return 0; for (i = 0; attr_name(bus->dev_attrs[i]); i++) { - error = device_create_file(dev,&bus->dev_attrs[i]); + error = device_create_file(dev, &bus->dev_attrs[i]); if (error) { while (--i >= 0) device_remove_file(dev, &bus->dev_attrs[i]); @@ -406,13 +407,13 @@ static int device_add_attrs(struct bus_type *bus, struct device *dev) return error; } -static void device_remove_attrs(struct bus_type * bus, struct device * dev) +static void device_remove_attrs(struct bus_type *bus, struct device *dev) { int i; if (bus->dev_attrs) { for (i = 0; attr_name(bus->dev_attrs[i]); i++) - device_remove_file(dev,&bus->dev_attrs[i]); + device_remove_file(dev, &bus->dev_attrs[i]); } } @@ -420,7 +421,7 @@ static void device_remove_attrs(struct bus_type * bus, struct device * dev) static int make_deprecated_bus_links(struct device *dev) { return sysfs_create_link(&dev->kobj, - &dev->bus->subsys.kobj, "bus"); + &dev->bus->p->subsys.kobj, "bus"); } static void remove_deprecated_bus_links(struct device *dev) @@ -433,28 +434,28 @@ static inline void remove_deprecated_bus_links(struct device *dev) { } #endif /** - * bus_add_device - add device to bus - * @dev: device being added + * bus_add_device - add device to bus + * @dev: device being added * - * - Add the device to its bus's list of devices. - * - Create link to device's bus. + * - Add the device to its bus's list of devices. + * - Create link to device's bus. */ -int bus_add_device(struct device * dev) +int bus_add_device(struct device *dev) { - struct bus_type * bus = bus_get(dev->bus); + struct bus_type *bus = bus_get(dev->bus); int error = 0; if (bus) { - pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id); + pr_debug("bus: '%s': add device %s\n", bus->name, dev->bus_id); error = device_add_attrs(bus, dev); if (error) goto out_put; - error = sysfs_create_link(&bus->devices.kobj, + error = sysfs_create_link(&bus->p->devices_kset->kobj, &dev->kobj, dev->bus_id); if (error) goto out_id; error = sysfs_create_link(&dev->kobj, - &dev->bus->subsys.kobj, "subsystem"); + &dev->bus->p->subsys.kobj, "subsystem"); if (error) goto out_subsys; error = make_deprecated_bus_links(dev); @@ -466,7 +467,7 @@ int bus_add_device(struct device * dev) out_deprecated: sysfs_remove_link(&dev->kobj, "subsystem"); out_subsys: - sysfs_remove_link(&bus->devices.kobj, dev->bus_id); + sysfs_remove_link(&bus->p->devices_kset->kobj, dev->bus_id); out_id: device_remove_attrs(bus, dev); out_put: @@ -475,56 +476,58 @@ int bus_add_device(struct device * dev) } /** - * bus_attach_device - add device to bus - * @dev: device tried to attach to a driver + * bus_attach_device - add device to bus + * @dev: device tried to attach to a driver * - * - Add device to bus's list of devices. - * - Try to attach to driver. + * - Add device to bus's list of devices. + * - Try to attach to driver. */ -void bus_attach_device(struct device * dev) +void bus_attach_device(struct device *dev) { struct bus_type *bus = dev->bus; int ret = 0; if (bus) { dev->is_registered = 1; - if (bus->drivers_autoprobe) + if (bus->p->drivers_autoprobe) ret = device_attach(dev); WARN_ON(ret < 0); if (ret >= 0) - klist_add_tail(&dev->knode_bus, &bus->klist_devices); + klist_add_tail(&dev->knode_bus, &bus->p->klist_devices); else dev->is_registered = 0; } } /** - * bus_remove_device - remove device from bus - * @dev: device to be removed + * bus_remove_device - remove device from bus + * @dev: device to be removed * - * - Remove symlink from bus's directory. - * - Delete device from bus's list. - * - Detach from its driver. - * - Drop reference taken in bus_add_device(). + * - Remove symlink from bus's directory. + * - Delete device from bus's list. + * - Detach from its driver. + * - Drop reference taken in bus_add_device(). */ -void bus_remove_device(struct device * dev) +void bus_remove_device(struct device *dev) { if (dev->bus) { sysfs_remove_link(&dev->kobj, "subsystem"); remove_deprecated_bus_links(dev); - sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id); + sysfs_remove_link(&dev->bus->p->devices_kset->kobj, + dev->bus_id); device_remove_attrs(dev->bus, dev); if (dev->is_registered) { dev->is_registered = 0; klist_del(&dev->knode_bus); } - pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id); + pr_debug("bus: '%s': remove device %s\n", + dev->bus->name, dev->bus_id); device_release_driver(dev); bus_put(dev->bus); } } -static int driver_add_attrs(struct bus_type * bus, struct device_driver * drv) +static int driver_add_attrs(struct bus_type *bus, struct device_driver *drv) { int error = 0; int i; @@ -533,19 +536,19 @@ static int driver_add_attrs(struct bus_type * bus, struct device_driver * drv) for (i = 0; attr_name(bus->drv_attrs[i]); i++) { error = driver_create_file(drv, &bus->drv_attrs[i]); if (error) - goto Err; + goto err; } } - Done: +done: return error; - Err: +err: while (--i >= 0) driver_remove_file(drv, &bus->drv_attrs[i]); - goto Done; + goto done; } - -static void driver_remove_attrs(struct bus_type * bus, struct device_driver * drv) +static void driver_remove_attrs(struct bus_type *bus, + struct device_driver *drv) { int i; @@ -616,39 +619,46 @@ static ssize_t driver_uevent_store(struct device_driver *drv, enum kobject_action action; if (kobject_action_type(buf, count, &action) == 0) - kobject_uevent(&drv->kobj, action); + kobject_uevent(&drv->p->kobj, action); return count; } static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store); /** - * bus_add_driver - Add a driver to the bus. - * @drv: driver. - * + * bus_add_driver - Add a driver to the bus. + * @drv: driver. */ int bus_add_driver(struct device_driver *drv) { - struct bus_type * bus = bus_get(drv->bus); + struct bus_type *bus; + struct driver_private *priv; int error = 0; + bus = bus_get(drv->bus); if (!bus) return -EINVAL; - pr_debug("bus %s: add driver %s\n", bus->name, drv->name); - error = kobject_set_name(&drv->kobj, "%s", drv->name); - if (error) - goto out_put_bus; - drv->kobj.kset = &bus->drivers; - error = kobject_register(&drv->kobj); + pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name); + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + klist_init(&priv->klist_devices, NULL, NULL); + priv->driver = drv; + drv->p = priv; + priv->kobj.kset = bus->p->drivers_kset; + error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL, + "%s", drv->name); if (error) goto out_put_bus; - if (drv->bus->drivers_autoprobe) { + if (drv->bus->p->drivers_autoprobe) { error = driver_attach(drv); if (error) goto out_unregister; } - klist_add_tail(&drv->knode_bus, &bus->klist_drivers); + klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); module_add_driver(drv->owner, drv); error = driver_create_file(drv, &driver_attr_uevent); @@ -669,24 +679,24 @@ int bus_add_driver(struct device_driver *drv) __FUNCTION__, drv->name); } + kobject_uevent(&priv->kobj, KOBJ_ADD); return error; out_unregister: - kobject_unregister(&drv->kobj); + kobject_put(&priv->kobj); out_put_bus: bus_put(bus); return error; } /** - * bus_remove_driver - delete driver from bus's knowledge. - * @drv: driver. + * bus_remove_driver - delete driver from bus's knowledge. + * @drv: driver. * - * Detach the driver from the devices it controls, and remove - * it from its bus's list of drivers. Finally, we drop the reference - * to the bus we took in bus_add_driver(). + * Detach the driver from the devices it controls, and remove + * it from its bus's list of drivers. Finally, we drop the reference + * to the bus we took in bus_add_driver(). */ - -void bus_remove_driver(struct device_driver * drv) +void bus_remove_driver(struct device_driver *drv) { if (!drv->bus) return; @@ -694,18 +704,17 @@ void bus_remove_driver(struct device_driver * drv) remove_bind_files(drv); driver_remove_attrs(drv->bus, drv); driver_remove_file(drv, &driver_attr_uevent); - klist_remove(&drv->knode_bus); - pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name); + klist_remove(&drv->p->knode_bus); + pr_debug("bus: '%s': remove driver %s\n", drv->bus->name, drv->name); driver_detach(drv); module_remove_driver(drv); - kobject_unregister(&drv->kobj); + kobject_put(&drv->p->kobj); bus_put(drv->bus); } - /* Helper for bus_rescan_devices's iter */ static int __must_check bus_rescan_devices_helper(struct device *dev, - void *data) + void *data) { int ret = 0; @@ -727,10 +736,11 @@ static int __must_check bus_rescan_devices_helper(struct device *dev, * attached and rescan it against existing drivers to see if it matches * any by calling device_attach() for the unbound devices. */ -int bus_rescan_devices(struct bus_type * bus) +int bus_rescan_devices(struct bus_type *bus) { return bus_for_each_dev(bus, NULL, NULL, bus_rescan_devices_helper); } +EXPORT_SYMBOL_GPL(bus_rescan_devices); /** * device_reprobe - remove driver for a device and probe for a new driver @@ -755,55 +765,55 @@ int device_reprobe(struct device *dev) EXPORT_SYMBOL_GPL(device_reprobe); /** - * find_bus - locate bus by name. - * @name: name of bus. + * find_bus - locate bus by name. + * @name: name of bus. * - * Call kset_find_obj() to iterate over list of buses to - * find a bus by name. Return bus if found. + * Call kset_find_obj() to iterate over list of buses to + * find a bus by name. Return bus if found. * - * Note that kset_find_obj increments bus' reference count. + * Note that kset_find_obj increments bus' reference count. */ #if 0 -struct bus_type * find_bus(char * name) +struct bus_type *find_bus(char *name) { - struct kobject * k = kset_find_obj(&bus_subsys.kset, name); + struct kobject *k = kset_find_obj(bus_kset, name); return k ? to_bus(k) : NULL; } #endif /* 0 */ /** - * bus_add_attrs - Add default attributes for this bus. - * @bus: Bus that has just been registered. + * bus_add_attrs - Add default attributes for this bus. + * @bus: Bus that has just been registered. */ -static int bus_add_attrs(struct bus_type * bus) +static int bus_add_attrs(struct bus_type *bus) { int error = 0; int i; if (bus->bus_attrs) { for (i = 0; attr_name(bus->bus_attrs[i]); i++) { - error = bus_create_file(bus,&bus->bus_attrs[i]); + error = bus_create_file(bus, &bus->bus_attrs[i]); if (error) - goto Err; + goto err; } } - Done: +done: return error; - Err: +err: while (--i >= 0) - bus_remove_file(bus,&bus->bus_attrs[i]); - goto Done; + bus_remove_file(bus, &bus->bus_attrs[i]); + goto done; } -static void bus_remove_attrs(struct bus_type * bus) +static void bus_remove_attrs(struct bus_type *bus) { int i; if (bus->bus_attrs) { for (i = 0; attr_name(bus->bus_attrs[i]); i++) - bus_remove_file(bus,&bus->bus_attrs[i]); + bus_remove_file(bus, &bus->bus_attrs[i]); } } @@ -827,32 +837,42 @@ static ssize_t bus_uevent_store(struct bus_type *bus, enum kobject_action action; if (kobject_action_type(buf, count, &action) == 0) - kobject_uevent(&bus->subsys.kobj, action); + kobject_uevent(&bus->p->subsys.kobj, action); return count; } static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store); /** - * bus_register - register a bus with the system. - * @bus: bus. + * bus_register - register a bus with the system. + * @bus: bus. * - * Once we have that, we registered the bus with the kobject - * infrastructure, then register the children subsystems it has: - * the devices and drivers that belong to the bus. + * Once we have that, we registered the bus with the kobject + * infrastructure, then register the children subsystems it has: + * the devices and drivers that belong to the bus. */ -int bus_register(struct bus_type * bus) +int bus_register(struct bus_type *bus) { int retval; + struct bus_type_private *priv; + + priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL); + if (!priv) + return -ENOMEM; - BLOCKING_INIT_NOTIFIER_HEAD(&bus->bus_notifier); + priv->bus = bus; + bus->p = priv; - retval = kobject_set_name(&bus->subsys.kobj, "%s", bus->name); + BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier); + + retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name); if (retval) goto out; - bus->subsys.kobj.kset = &bus_subsys; + priv->subsys.kobj.kset = bus_kset; + priv->subsys.kobj.ktype = &bus_ktype; + priv->drivers_autoprobe = 1; - retval = subsystem_register(&bus->subsys); + retval = kset_register(&priv->subsys); if (retval) goto out; @@ -860,23 +880,23 @@ int bus_register(struct bus_type * bus) if (retval) goto bus_uevent_fail; - kobject_set_name(&bus->devices.kobj, "devices"); - bus->devices.kobj.parent = &bus->subsys.kobj; - retval = kset_register(&bus->devices); - if (retval) + priv->devices_kset = kset_create_and_add("devices", NULL, + &priv->subsys.kobj); + if (!priv->devices_kset) { + retval = -ENOMEM; goto bus_devices_fail; + } - kobject_set_name(&bus->drivers.kobj, "drivers"); - bus->drivers.kobj.parent = &bus->subsys.kobj; - bus->drivers.ktype = &driver_ktype; - retval = kset_register(&bus->drivers); - if (retval) + priv->drivers_kset = kset_create_and_add("drivers", NULL, + &priv->subsys.kobj); + if (!priv->drivers_kset) { + retval = -ENOMEM; goto bus_drivers_fail; + } - klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put); - klist_init(&bus->klist_drivers, NULL, NULL); + klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put); + klist_init(&priv->klist_drivers, NULL, NULL); - bus->drivers_autoprobe = 1; retval = add_probe_files(bus); if (retval) goto bus_probe_files_fail; @@ -885,66 +905,73 @@ int bus_register(struct bus_type * bus) if (retval) goto bus_attrs_fail; - pr_debug("bus type '%s' registered\n", bus->name); + pr_debug("bus: '%s': registered\n", bus->name); return 0; bus_attrs_fail: remove_probe_files(bus); bus_probe_files_fail: - kset_unregister(&bus->drivers); + kset_unregister(bus->p->drivers_kset); bus_drivers_fail: - kset_unregister(&bus->devices); + kset_unregister(bus->p->devices_kset); bus_devices_fail: bus_remove_file(bus, &bus_attr_uevent); bus_uevent_fail: - subsystem_unregister(&bus->subsys); + kset_unregister(&bus->p->subsys); + kfree(bus->p); out: return retval; } +EXPORT_SYMBOL_GPL(bus_register); /** - * bus_unregister - remove a bus from the system - * @bus: bus. + * bus_unregister - remove a bus from the system + * @bus: bus. * - * Unregister the child subsystems and the bus itself. - * Finally, we call bus_put() to release the refcount + * Unregister the child subsystems and the bus itself. + * Finally, we call bus_put() to release the refcount */ -void bus_unregister(struct bus_type * bus) +void bus_unregister(struct bus_type *bus) { - pr_debug("bus %s: unregistering\n", bus->name); + pr_debug("bus: '%s': unregistering\n", bus->name); bus_remove_attrs(bus); remove_probe_files(bus); - kset_unregister(&bus->drivers); - kset_unregister(&bus->devices); + kset_unregister(bus->p->drivers_kset); + kset_unregister(bus->p->devices_kset); bus_remove_file(bus, &bus_attr_uevent); - subsystem_unregister(&bus->subsys); + kset_unregister(&bus->p->subsys); + kfree(bus->p); } +EXPORT_SYMBOL_GPL(bus_unregister); int bus_register_notifier(struct bus_type *bus, struct notifier_block *nb) { - return blocking_notifier_chain_register(&bus->bus_notifier, nb); + return blocking_notifier_chain_register(&bus->p->bus_notifier, nb); } EXPORT_SYMBOL_GPL(bus_register_notifier); int bus_unregister_notifier(struct bus_type *bus, struct notifier_block *nb) { - return blocking_notifier_chain_unregister(&bus->bus_notifier, nb); + return blocking_notifier_chain_unregister(&bus->p->bus_notifier, nb); } EXPORT_SYMBOL_GPL(bus_unregister_notifier); -int __init buses_init(void) +struct kset *bus_get_kset(struct bus_type *bus) { - return subsystem_register(&bus_subsys); + return &bus->p->subsys; } +EXPORT_SYMBOL_GPL(bus_get_kset); +struct klist *bus_get_device_klist(struct bus_type *bus) +{ + return &bus->p->klist_devices; +} +EXPORT_SYMBOL_GPL(bus_get_device_klist); -EXPORT_SYMBOL_GPL(bus_for_each_dev); -EXPORT_SYMBOL_GPL(bus_find_device); -EXPORT_SYMBOL_GPL(bus_for_each_drv); - -EXPORT_SYMBOL_GPL(bus_register); -EXPORT_SYMBOL_GPL(bus_unregister); -EXPORT_SYMBOL_GPL(bus_rescan_devices); - -EXPORT_SYMBOL_GPL(bus_create_file); -EXPORT_SYMBOL_GPL(bus_remove_file); +int __init buses_init(void) +{ + bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL); + if (!bus_kset) + return -ENOMEM; + return 0; +} diff --git a/drivers/base/class.c b/drivers/base/class.c index a863bb091e11db26e6e996dfa6fb341285d11991..59cf35894cfce832c814128baa495a2e35f4971b 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -17,16 +17,17 @@ #include <linux/kdev_t.h> #include <linux/err.h> #include <linux/slab.h> +#include <linux/genhd.h> #include "base.h" #define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr) #define to_class(obj) container_of(obj, struct class, subsys.kobj) -static ssize_t -class_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) +static ssize_t class_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) { - struct class_attribute * class_attr = to_class_attr(attr); - struct class * dc = to_class(kobj); + struct class_attribute *class_attr = to_class_attr(attr); + struct class *dc = to_class(kobj); ssize_t ret = -EIO; if (class_attr->show) @@ -34,12 +35,11 @@ class_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) return ret; } -static ssize_t -class_attr_store(struct kobject * kobj, struct attribute * attr, - const char * buf, size_t count) +static ssize_t class_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) { - struct class_attribute * class_attr = to_class_attr(attr); - struct class * dc = to_class(kobj); + struct class_attribute *class_attr = to_class_attr(attr); + struct class *dc = to_class(kobj); ssize_t ret = -EIO; if (class_attr->store) @@ -47,7 +47,7 @@ class_attr_store(struct kobject * kobj, struct attribute * attr, return ret; } -static void class_release(struct kobject * kobj) +static void class_release(struct kobject *kobj) { struct class *class = to_class(kobj); @@ -71,20 +71,20 @@ static struct kobj_type class_ktype = { }; /* Hotplug events for classes go to the class_obj subsys */ -static decl_subsys(class, &class_ktype, NULL); +static struct kset *class_kset; -int class_create_file(struct class * cls, const struct class_attribute * attr) +int class_create_file(struct class *cls, const struct class_attribute *attr) { int error; - if (cls) { + if (cls) error = sysfs_create_file(&cls->subsys.kobj, &attr->attr); - } else + else error = -EINVAL; return error; } -void class_remove_file(struct class * cls, const struct class_attribute * attr) +void class_remove_file(struct class *cls, const struct class_attribute *attr) { if (cls) sysfs_remove_file(&cls->subsys.kobj, &attr->attr); @@ -93,48 +93,48 @@ void class_remove_file(struct class * cls, const struct class_attribute * attr) static struct class *class_get(struct class *cls) { if (cls) - return container_of(kset_get(&cls->subsys), struct class, subsys); + return container_of(kset_get(&cls->subsys), + struct class, subsys); return NULL; } -static void class_put(struct class * cls) +static void class_put(struct class *cls) { if (cls) kset_put(&cls->subsys); } - -static int add_class_attrs(struct class * cls) +static int add_class_attrs(struct class *cls) { int i; int error = 0; if (cls->class_attrs) { for (i = 0; attr_name(cls->class_attrs[i]); i++) { - error = class_create_file(cls,&cls->class_attrs[i]); + error = class_create_file(cls, &cls->class_attrs[i]); if (error) - goto Err; + goto error; } } - Done: +done: return error; - Err: +error: while (--i >= 0) - class_remove_file(cls,&cls->class_attrs[i]); - goto Done; + class_remove_file(cls, &cls->class_attrs[i]); + goto done; } -static void remove_class_attrs(struct class * cls) +static void remove_class_attrs(struct class *cls) { int i; if (cls->class_attrs) { for (i = 0; attr_name(cls->class_attrs[i]); i++) - class_remove_file(cls,&cls->class_attrs[i]); + class_remove_file(cls, &cls->class_attrs[i]); } } -int class_register(struct class * cls) +int class_register(struct class *cls) { int error; @@ -149,9 +149,16 @@ int class_register(struct class * cls) if (error) return error; - cls->subsys.kobj.kset = &class_subsys; +#ifdef CONFIG_SYSFS_DEPRECATED + /* let the block class directory show up in the root of sysfs */ + if (cls != &block_class) + cls->subsys.kobj.kset = class_kset; +#else + cls->subsys.kobj.kset = class_kset; +#endif + cls->subsys.kobj.ktype = &class_ktype; - error = subsystem_register(&cls->subsys); + error = kset_register(&cls->subsys); if (!error) { error = add_class_attrs(class_get(cls)); class_put(cls); @@ -159,11 +166,11 @@ int class_register(struct class * cls) return error; } -void class_unregister(struct class * cls) +void class_unregister(struct class *cls) { pr_debug("device class '%s': unregistering\n", cls->name); remove_class_attrs(cls); - subsystem_unregister(&cls->subsys); + kset_unregister(&cls->subsys); } static void class_create_release(struct class *cls) @@ -241,8 +248,8 @@ void class_destroy(struct class *cls) /* Class Device Stuff */ -int class_device_create_file(struct class_device * class_dev, - const struct class_device_attribute * attr) +int class_device_create_file(struct class_device *class_dev, + const struct class_device_attribute *attr) { int error = -EINVAL; if (class_dev) @@ -250,8 +257,8 @@ int class_device_create_file(struct class_device * class_dev, return error; } -void class_device_remove_file(struct class_device * class_dev, - const struct class_device_attribute * attr) +void class_device_remove_file(struct class_device *class_dev, + const struct class_device_attribute *attr) { if (class_dev) sysfs_remove_file(&class_dev->kobj, &attr->attr); @@ -273,12 +280,11 @@ void class_device_remove_bin_file(struct class_device *class_dev, sysfs_remove_bin_file(&class_dev->kobj, attr); } -static ssize_t -class_device_attr_show(struct kobject * kobj, struct attribute * attr, - char * buf) +static ssize_t class_device_attr_show(struct kobject *kobj, + struct attribute *attr, char *buf) { - struct class_device_attribute * class_dev_attr = to_class_dev_attr(attr); - struct class_device * cd = to_class_dev(kobj); + struct class_device_attribute *class_dev_attr = to_class_dev_attr(attr); + struct class_device *cd = to_class_dev(kobj); ssize_t ret = 0; if (class_dev_attr->show) @@ -286,12 +292,12 @@ class_device_attr_show(struct kobject * kobj, struct attribute * attr, return ret; } -static ssize_t -class_device_attr_store(struct kobject * kobj, struct attribute * attr, - const char * buf, size_t count) +static ssize_t class_device_attr_store(struct kobject *kobj, + struct attribute *attr, + const char *buf, size_t count) { - struct class_device_attribute * class_dev_attr = to_class_dev_attr(attr); - struct class_device * cd = to_class_dev(kobj); + struct class_device_attribute *class_dev_attr = to_class_dev_attr(attr); + struct class_device *cd = to_class_dev(kobj); ssize_t ret = 0; if (class_dev_attr->store) @@ -304,10 +310,10 @@ static struct sysfs_ops class_dev_sysfs_ops = { .store = class_device_attr_store, }; -static void class_dev_release(struct kobject * kobj) +static void class_dev_release(struct kobject *kobj) { struct class_device *cd = to_class_dev(kobj); - struct class * cls = cd->class; + struct class *cls = cd->class; pr_debug("device class '%s': release.\n", cd->class_id); @@ -316,8 +322,8 @@ static void class_dev_release(struct kobject * kobj) else if (cls->release) cls->release(cd); else { - printk(KERN_ERR "Class Device '%s' does not have a release() function, " - "it is broken and must be fixed.\n", + printk(KERN_ERR "Class Device '%s' does not have a release() " + "function, it is broken and must be fixed.\n", cd->class_id); WARN_ON(1); } @@ -428,7 +434,8 @@ static int class_uevent(struct kset *kset, struct kobject *kobj, add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name); if (dev->driver) - add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name); + add_uevent_var(env, "PHYSDEVDRIVER=%s", + dev->driver->name); } if (class_dev->uevent) { @@ -452,43 +459,49 @@ static struct kset_uevent_ops class_uevent_ops = { .uevent = class_uevent, }; -static decl_subsys(class_obj, &class_device_ktype, &class_uevent_ops); - +/* + * DO NOT copy how this is created, kset_create_and_add() should be + * called, but this is a hold-over from the old-way and will be deleted + * entirely soon. + */ +static struct kset class_obj_subsys = { + .uevent_ops = &class_uevent_ops, +}; -static int class_device_add_attrs(struct class_device * cd) +static int class_device_add_attrs(struct class_device *cd) { int i; int error = 0; - struct class * cls = cd->class; + struct class *cls = cd->class; if (cls->class_dev_attrs) { for (i = 0; attr_name(cls->class_dev_attrs[i]); i++) { error = class_device_create_file(cd, - &cls->class_dev_attrs[i]); + &cls->class_dev_attrs[i]); if (error) - goto Err; + goto err; } } - Done: +done: return error; - Err: +err: while (--i >= 0) - class_device_remove_file(cd,&cls->class_dev_attrs[i]); - goto Done; + class_device_remove_file(cd, &cls->class_dev_attrs[i]); + goto done; } -static void class_device_remove_attrs(struct class_device * cd) +static void class_device_remove_attrs(struct class_device *cd) { int i; - struct class * cls = cd->class; + struct class *cls = cd->class; if (cls->class_dev_attrs) { for (i = 0; attr_name(cls->class_dev_attrs[i]); i++) - class_device_remove_file(cd,&cls->class_dev_attrs[i]); + class_device_remove_file(cd, &cls->class_dev_attrs[i]); } } -static int class_device_add_groups(struct class_device * cd) +static int class_device_add_groups(struct class_device *cd) { int i; int error = 0; @@ -498,7 +511,8 @@ static int class_device_add_groups(struct class_device * cd) error = sysfs_create_group(&cd->kobj, cd->groups[i]); if (error) { while (--i >= 0) - sysfs_remove_group(&cd->kobj, cd->groups[i]); + sysfs_remove_group(&cd->kobj, + cd->groups[i]); goto out; } } @@ -507,14 +521,12 @@ static int class_device_add_groups(struct class_device * cd) return error; } -static void class_device_remove_groups(struct class_device * cd) +static void class_device_remove_groups(struct class_device *cd) { int i; - if (cd->groups) { - for (i = 0; cd->groups[i]; i++) { + if (cd->groups) + for (i = 0; cd->groups[i]; i++) sysfs_remove_group(&cd->kobj, cd->groups[i]); - } - } } static ssize_t show_dev(struct class_device *class_dev, char *buf) @@ -537,8 +549,8 @@ static struct class_device_attribute class_uevent_attr = void class_device_initialize(struct class_device *class_dev) { - kobj_set_kset_s(class_dev, class_obj_subsys); - kobject_init(&class_dev->kobj); + class_dev->kobj.kset = &class_obj_subsys; + kobject_init(&class_dev->kobj, &class_device_ktype); INIT_LIST_HEAD(&class_dev->node); } @@ -566,16 +578,13 @@ int class_device_add(struct class_device *class_dev) class_dev->class_id); /* first, register with generic layer. */ - error = kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id); - if (error) - goto out2; - if (parent_class_dev) class_dev->kobj.parent = &parent_class_dev->kobj; else class_dev->kobj.parent = &parent_class->subsys.kobj; - error = kobject_add(&class_dev->kobj); + error = kobject_add(&class_dev->kobj, class_dev->kobj.parent, + "%s", class_dev->class_id); if (error) goto out2; @@ -642,7 +651,7 @@ int class_device_add(struct class_device *class_dev) out3: kobject_del(&class_dev->kobj); out2: - if(parent_class_dev) + if (parent_class_dev) class_device_put(parent_class_dev); class_put(parent_class); out1: @@ -659,9 +668,11 @@ int class_device_register(struct class_device *class_dev) /** * class_device_create - creates a class device and registers it with sysfs * @cls: pointer to the struct class that this device should be registered to. - * @parent: pointer to the parent struct class_device of this new device, if any. + * @parent: pointer to the parent struct class_device of this new device, if + * any. * @devt: the dev_t for the char device to be added. - * @device: a pointer to a struct device that is assiociated with this class device. + * @device: a pointer to a struct device that is assiociated with this class + * device. * @fmt: string for the class device's name * * This function can be used by char device classes. A struct @@ -785,7 +796,7 @@ void class_device_destroy(struct class *cls, dev_t devt) class_device_unregister(class_dev); } -struct class_device * class_device_get(struct class_device *class_dev) +struct class_device *class_device_get(struct class_device *class_dev) { if (class_dev) return to_class_dev(kobject_get(&class_dev->kobj)); @@ -798,6 +809,139 @@ void class_device_put(struct class_device *class_dev) kobject_put(&class_dev->kobj); } +/** + * class_for_each_device - device iterator + * @class: the class we're iterating + * @data: data for the callback + * @fn: function to be called for each device + * + * Iterate over @class's list of devices, and call @fn for each, + * passing it @data. + * + * We check the return of @fn each time. If it returns anything + * other than 0, we break out and return that value. + * + * Note, we hold class->sem in this function, so it can not be + * re-acquired in @fn, otherwise it will self-deadlocking. For + * example, calls to add or remove class members would be verboten. + */ +int class_for_each_device(struct class *class, void *data, + int (*fn)(struct device *, void *)) +{ + struct device *dev; + int error = 0; + + if (!class) + return -EINVAL; + down(&class->sem); + list_for_each_entry(dev, &class->devices, node) { + dev = get_device(dev); + if (dev) { + error = fn(dev, data); + put_device(dev); + } else + error = -ENODEV; + if (error) + break; + } + up(&class->sem); + + return error; +} +EXPORT_SYMBOL_GPL(class_for_each_device); + +/** + * class_find_device - device iterator for locating a particular device + * @class: the class we're iterating + * @data: data for the match function + * @match: function to check device + * + * This is similar to the class_for_each_dev() function above, but it + * returns a reference to a device that is 'found' for later use, as + * determined by the @match callback. + * + * The callback should return 0 if the device doesn't match and non-zero + * if it does. If the callback returns non-zero, this function will + * return to the caller and not iterate over any more devices. + + * Note, you will need to drop the reference with put_device() after use. + * + * We hold class->sem in this function, so it can not be + * re-acquired in @match, otherwise it will self-deadlocking. For + * example, calls to add or remove class members would be verboten. + */ +struct device *class_find_device(struct class *class, void *data, + int (*match)(struct device *, void *)) +{ + struct device *dev; + int found = 0; + + if (!class) + return NULL; + + down(&class->sem); + list_for_each_entry(dev, &class->devices, node) { + dev = get_device(dev); + if (dev) { + if (match(dev, data)) { + found = 1; + break; + } else + put_device(dev); + } else + break; + } + up(&class->sem); + + return found ? dev : NULL; +} +EXPORT_SYMBOL_GPL(class_find_device); + +/** + * class_find_child - device iterator for locating a particular class_device + * @class: the class we're iterating + * @data: data for the match function + * @match: function to check class_device + * + * This function returns a reference to a class_device that is 'found' for + * later use, as determined by the @match callback. + * + * The callback should return 0 if the class_device doesn't match and non-zero + * if it does. If the callback returns non-zero, this function will + * return to the caller and not iterate over any more class_devices. + * + * Note, you will need to drop the reference with class_device_put() after use. + * + * We hold class->sem in this function, so it can not be + * re-acquired in @match, otherwise it will self-deadlocking. For + * example, calls to add or remove class members would be verboten. + */ +struct class_device *class_find_child(struct class *class, void *data, + int (*match)(struct class_device *, void *)) +{ + struct class_device *dev; + int found = 0; + + if (!class) + return NULL; + + down(&class->sem); + list_for_each_entry(dev, &class->children, node) { + dev = class_device_get(dev); + if (dev) { + if (match(dev, data)) { + found = 1; + break; + } else + class_device_put(dev); + } else + break; + } + up(&class->sem); + + return found ? dev : NULL; +} +EXPORT_SYMBOL_GPL(class_find_child); int class_interface_register(struct class_interface *class_intf) { @@ -829,7 +973,7 @@ int class_interface_register(struct class_interface *class_intf) void class_interface_unregister(struct class_interface *class_intf) { - struct class * parent = class_intf->class; + struct class *parent = class_intf->class; struct class_device *class_dev; struct device *dev; @@ -853,15 +997,14 @@ void class_interface_unregister(struct class_interface *class_intf) int __init classes_init(void) { - int retval; - - retval = subsystem_register(&class_subsys); - if (retval) - return retval; + class_kset = kset_create_and_add("class", NULL, NULL); + if (!class_kset) + return -ENOMEM; /* ick, this is ugly, the things we go through to keep from showing up * in sysfs... */ kset_init(&class_obj_subsys); + kobject_set_name(&class_obj_subsys.kobj, "class_obj"); if (!class_obj_subsys.kobj.parent) class_obj_subsys.kobj.parent = &class_obj_subsys.kobj; return 0; diff --git a/drivers/base/core.c b/drivers/base/core.c index 2683eac30c68138220500217ddfdc550a7b24e81..edf3bbeb8d6a0af7438119b915aafb3f0111617d 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -18,14 +18,14 @@ #include <linux/string.h> #include <linux/kdev_t.h> #include <linux/notifier.h> - +#include <linux/genhd.h> #include <asm/semaphore.h> #include "base.h" #include "power/power.h" -int (*platform_notify)(struct device * dev) = NULL; -int (*platform_notify_remove)(struct device * dev) = NULL; +int (*platform_notify)(struct device *dev) = NULL; +int (*platform_notify_remove)(struct device *dev) = NULL; /* * sysfs bindings for devices. @@ -51,11 +51,11 @@ EXPORT_SYMBOL(dev_driver_string); #define to_dev(obj) container_of(obj, struct device, kobj) #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr) -static ssize_t -dev_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) +static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) { - struct device_attribute * dev_attr = to_dev_attr(attr); - struct device * dev = to_dev(kobj); + struct device_attribute *dev_attr = to_dev_attr(attr); + struct device *dev = to_dev(kobj); ssize_t ret = -EIO; if (dev_attr->show) @@ -63,12 +63,11 @@ dev_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) return ret; } -static ssize_t -dev_attr_store(struct kobject * kobj, struct attribute * attr, - const char * buf, size_t count) +static ssize_t dev_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) { - struct device_attribute * dev_attr = to_dev_attr(attr); - struct device * dev = to_dev(kobj); + struct device_attribute *dev_attr = to_dev_attr(attr); + struct device *dev = to_dev(kobj); ssize_t ret = -EIO; if (dev_attr->store) @@ -90,9 +89,9 @@ static struct sysfs_ops dev_sysfs_ops = { * reaches 0. We forward the call to the device's release * method, which should handle actually freeing the structure. */ -static void device_release(struct kobject * kobj) +static void device_release(struct kobject *kobj) { - struct device * dev = to_dev(kobj); + struct device *dev = to_dev(kobj); if (dev->release) dev->release(dev); @@ -101,8 +100,8 @@ static void device_release(struct kobject * kobj) else if (dev->class && dev->class->dev_release) dev->class->dev_release(dev); else { - printk(KERN_ERR "Device '%s' does not have a release() function, " - "it is broken and must be fixed.\n", + printk(KERN_ERR "Device '%s' does not have a release() " + "function, it is broken and must be fixed.\n", dev->bus_id); WARN_ON(1); } @@ -185,7 +184,8 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name); if (dev->driver) - add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name); + add_uevent_var(env, "PHYSDEVDRIVER=%s", + dev->driver->name); } #endif @@ -193,15 +193,16 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, if (dev->bus && dev->bus->uevent) { retval = dev->bus->uevent(dev, env); if (retval) - pr_debug ("%s: bus uevent() returned %d\n", - __FUNCTION__, retval); + pr_debug("device: '%s': %s: bus uevent() returned %d\n", + dev->bus_id, __FUNCTION__, retval); } /* have the class specific function add its stuff */ if (dev->class && dev->class->dev_uevent) { retval = dev->class->dev_uevent(dev, env); if (retval) - pr_debug("%s: class uevent() returned %d\n", + pr_debug("device: '%s': %s: class uevent() " + "returned %d\n", dev->bus_id, __FUNCTION__, retval); } @@ -209,7 +210,8 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, if (dev->type && dev->type->uevent) { retval = dev->type->uevent(dev, env); if (retval) - pr_debug("%s: dev_type uevent() returned %d\n", + pr_debug("device: '%s': %s: dev_type uevent() " + "returned %d\n", dev->bus_id, __FUNCTION__, retval); } @@ -325,7 +327,8 @@ static int device_add_groups(struct device *dev, error = sysfs_create_group(&dev->kobj, groups[i]); if (error) { while (--i >= 0) - sysfs_remove_group(&dev->kobj, groups[i]); + sysfs_remove_group(&dev->kobj, + groups[i]); break; } } @@ -401,20 +404,15 @@ static ssize_t show_dev(struct device *dev, struct device_attribute *attr, static struct device_attribute devt_attr = __ATTR(dev, S_IRUGO, show_dev, NULL); -/* - * devices_subsys - structure to be registered with kobject core. - */ - -decl_subsys(devices, &device_ktype, &device_uevent_ops); - +/* kset to create /sys/devices/ */ +struct kset *devices_kset; /** - * device_create_file - create sysfs attribute file for device. - * @dev: device. - * @attr: device attribute descriptor. + * device_create_file - create sysfs attribute file for device. + * @dev: device. + * @attr: device attribute descriptor. */ - -int device_create_file(struct device * dev, struct device_attribute * attr) +int device_create_file(struct device *dev, struct device_attribute *attr) { int error = 0; if (get_device(dev)) { @@ -425,12 +423,11 @@ int device_create_file(struct device * dev, struct device_attribute * attr) } /** - * device_remove_file - remove sysfs attribute file. - * @dev: device. - * @attr: device attribute descriptor. + * device_remove_file - remove sysfs attribute file. + * @dev: device. + * @attr: device attribute descriptor. */ - -void device_remove_file(struct device * dev, struct device_attribute * attr) +void device_remove_file(struct device *dev, struct device_attribute *attr) { if (get_device(dev)) { sysfs_remove_file(&dev->kobj, &attr->attr); @@ -511,22 +508,20 @@ static void klist_children_put(struct klist_node *n) put_device(dev); } - /** - * device_initialize - init device structure. - * @dev: device. + * device_initialize - init device structure. + * @dev: device. * - * This prepares the device for use by other layers, - * including adding it to the device hierarchy. - * It is the first half of device_register(), if called by - * that, though it can also be called separately, so one - * may use @dev's fields (e.g. the refcount). + * This prepares the device for use by other layers, + * including adding it to the device hierarchy. + * It is the first half of device_register(), if called by + * that, though it can also be called separately, so one + * may use @dev's fields (e.g. the refcount). */ - void device_initialize(struct device *dev) { - kobj_set_kset_s(dev, devices_subsys); - kobject_init(&dev->kobj); + dev->kobj.kset = devices_kset; + kobject_init(&dev->kobj, &device_ktype); klist_init(&dev->klist_children, klist_children_get, klist_children_put); INIT_LIST_HEAD(&dev->dma_pools); @@ -539,36 +534,39 @@ void device_initialize(struct device *dev) } #ifdef CONFIG_SYSFS_DEPRECATED -static struct kobject * get_device_parent(struct device *dev, - struct device *parent) +static struct kobject *get_device_parent(struct device *dev, + struct device *parent) { - /* - * Set the parent to the class, not the parent device - * for topmost devices in class hierarchy. - * This keeps sysfs from having a symlink to make old - * udevs happy - */ + /* class devices without a parent live in /sys/class/<classname>/ */ if (dev->class && (!parent || parent->class != dev->class)) return &dev->class->subsys.kobj; + /* all other devices keep their parent */ else if (parent) return &parent->kobj; return NULL; } + +static inline void cleanup_device_parent(struct device *dev) {} +static inline void cleanup_glue_dir(struct device *dev, + struct kobject *glue_dir) {} #else static struct kobject *virtual_device_parent(struct device *dev) { static struct kobject *virtual_dir = NULL; if (!virtual_dir) - virtual_dir = kobject_add_dir(&devices_subsys.kobj, "virtual"); + virtual_dir = kobject_create_and_add("virtual", + &devices_kset->kobj); return virtual_dir; } -static struct kobject * get_device_parent(struct device *dev, - struct device *parent) +static struct kobject *get_device_parent(struct device *dev, + struct device *parent) { + int retval; + if (dev->class) { struct kobject *kobj = NULL; struct kobject *parent_kobj; @@ -576,8 +574,8 @@ static struct kobject * get_device_parent(struct device *dev, /* * If we have no parent, we live in "virtual". - * Class-devices with a bus-device as parent, live - * in a class-directory to prevent namespace collisions. + * Class-devices with a non class-device as parent, live + * in a "glue" directory to prevent namespace collisions. */ if (parent == NULL) parent_kobj = virtual_device_parent(dev); @@ -598,25 +596,45 @@ static struct kobject * get_device_parent(struct device *dev, return kobj; /* or create a new class-directory at the parent device */ - return kobject_kset_add_dir(&dev->class->class_dirs, - parent_kobj, dev->class->name); + k = kobject_create(); + if (!k) + return NULL; + k->kset = &dev->class->class_dirs; + retval = kobject_add(k, parent_kobj, "%s", dev->class->name); + if (retval < 0) { + kobject_put(k); + return NULL; + } + /* do not emit an uevent for this simple "glue" directory */ + return k; } if (parent) return &parent->kobj; return NULL; } + +static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir) +{ + /* see if we live in a "glue" directory */ + if (!dev->class || glue_dir->kset != &dev->class->class_dirs) + return; + + kobject_put(glue_dir); +} + +static void cleanup_device_parent(struct device *dev) +{ + cleanup_glue_dir(dev, dev->kobj.parent); +} #endif -static int setup_parent(struct device *dev, struct device *parent) +static void setup_parent(struct device *dev, struct device *parent) { struct kobject *kobj; kobj = get_device_parent(dev, parent); - if (IS_ERR(kobj)) - return PTR_ERR(kobj); if (kobj) dev->kobj.parent = kobj; - return 0; } static int device_add_class_symlinks(struct device *dev) @@ -625,65 +643,76 @@ static int device_add_class_symlinks(struct device *dev) if (!dev->class) return 0; + error = sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj, "subsystem"); if (error) goto out; - /* - * If this is not a "fake" compatible device, then create the - * symlink from the class to the device. - */ - if (dev->kobj.parent != &dev->class->subsys.kobj) { + +#ifdef CONFIG_SYSFS_DEPRECATED + /* stacked class devices need a symlink in the class directory */ + if (dev->kobj.parent != &dev->class->subsys.kobj && + dev->type != &part_type) { error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj, dev->bus_id); if (error) goto out_subsys; } - if (dev->parent) { -#ifdef CONFIG_SYSFS_DEPRECATED - { - struct device *parent = dev->parent; - char *class_name; - - /* - * In old sysfs stacked class devices had 'device' - * link pointing to real device instead of parent - */ - while (parent->class && !parent->bus && parent->parent) - parent = parent->parent; - - error = sysfs_create_link(&dev->kobj, - &parent->kobj, - "device"); - if (error) - goto out_busid; - class_name = make_class_name(dev->class->name, - &dev->kobj); - if (class_name) - error = sysfs_create_link(&dev->parent->kobj, - &dev->kobj, class_name); - kfree(class_name); - if (error) - goto out_device; - } -#else - error = sysfs_create_link(&dev->kobj, &dev->parent->kobj, + if (dev->parent && dev->type != &part_type) { + struct device *parent = dev->parent; + char *class_name; + + /* + * stacked class devices have the 'device' link + * pointing to the bus device instead of the parent + */ + while (parent->class && !parent->bus && parent->parent) + parent = parent->parent; + + error = sysfs_create_link(&dev->kobj, + &parent->kobj, "device"); if (error) goto out_busid; -#endif + + class_name = make_class_name(dev->class->name, + &dev->kobj); + if (class_name) + error = sysfs_create_link(&dev->parent->kobj, + &dev->kobj, class_name); + kfree(class_name); + if (error) + goto out_device; } return 0; -#ifdef CONFIG_SYSFS_DEPRECATED out_device: - if (dev->parent) + if (dev->parent && dev->type != &part_type) sysfs_remove_link(&dev->kobj, "device"); -#endif out_busid: - if (dev->kobj.parent != &dev->class->subsys.kobj) + if (dev->kobj.parent != &dev->class->subsys.kobj && + dev->type != &part_type) sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); +#else + /* link in the class directory pointing to the device */ + error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj, + dev->bus_id); + if (error) + goto out_subsys; + + if (dev->parent && dev->type != &part_type) { + error = sysfs_create_link(&dev->kobj, &dev->parent->kobj, + "device"); + if (error) + goto out_busid; + } + return 0; + +out_busid: + sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); +#endif + out_subsys: sysfs_remove_link(&dev->kobj, "subsystem"); out: @@ -694,8 +723,9 @@ static void device_remove_class_symlinks(struct device *dev) { if (!dev->class) return; - if (dev->parent) { + #ifdef CONFIG_SYSFS_DEPRECATED + if (dev->parent && dev->type != &part_type) { char *class_name; class_name = make_class_name(dev->class->name, &dev->kobj); @@ -703,45 +733,59 @@ static void device_remove_class_symlinks(struct device *dev) sysfs_remove_link(&dev->parent->kobj, class_name); kfree(class_name); } -#endif sysfs_remove_link(&dev->kobj, "device"); } - if (dev->kobj.parent != &dev->class->subsys.kobj) + + if (dev->kobj.parent != &dev->class->subsys.kobj && + dev->type != &part_type) sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); +#else + if (dev->parent && dev->type != &part_type) + sysfs_remove_link(&dev->kobj, "device"); + + sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); +#endif + sysfs_remove_link(&dev->kobj, "subsystem"); } /** - * device_add - add device to device hierarchy. - * @dev: device. + * device_add - add device to device hierarchy. + * @dev: device. * - * This is part 2 of device_register(), though may be called - * separately _iff_ device_initialize() has been called separately. + * This is part 2 of device_register(), though may be called + * separately _iff_ device_initialize() has been called separately. * - * This adds it to the kobject hierarchy via kobject_add(), adds it - * to the global and sibling lists for the device, then - * adds it to the other relevant subsystems of the driver model. + * This adds it to the kobject hierarchy via kobject_add(), adds it + * to the global and sibling lists for the device, then + * adds it to the other relevant subsystems of the driver model. */ int device_add(struct device *dev) { struct device *parent = NULL; struct class_interface *class_intf; - int error = -EINVAL; + int error; + + error = pm_sleep_lock(); + if (error) { + dev_warn(dev, "Suspicious %s during suspend\n", __FUNCTION__); + dump_stack(); + return error; + } dev = get_device(dev); - if (!dev || !strlen(dev->bus_id)) + if (!dev || !strlen(dev->bus_id)) { + error = -EINVAL; goto Error; + } - pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id); + pr_debug("device: '%s': %s\n", dev->bus_id, __FUNCTION__); parent = get_device(dev->parent); - error = setup_parent(dev, parent); - if (error) - goto Error; + setup_parent(dev, parent); /* first, register with generic layer. */ - kobject_set_name(&dev->kobj, "%s", dev->bus_id); - error = kobject_add(&dev->kobj); + error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id); if (error) goto Error; @@ -751,7 +795,7 @@ int device_add(struct device *dev) /* notify clients of device entry (new way) */ if (dev->bus) - blocking_notifier_call_chain(&dev->bus->bus_notifier, + blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_ADD_DEVICE, dev); error = device_create_file(dev, &uevent_attr); @@ -795,13 +839,14 @@ int device_add(struct device *dev) } Done: put_device(dev); + pm_sleep_unlock(); return error; BusError: device_pm_remove(dev); dpm_sysfs_remove(dev); PMError: if (dev->bus) - blocking_notifier_call_chain(&dev->bus->bus_notifier, + blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_DEL_DEVICE, dev); device_remove_attrs(dev); AttrsError: @@ -809,124 +854,84 @@ int device_add(struct device *dev) SymlinkError: if (MAJOR(dev->devt)) device_remove_file(dev, &devt_attr); - - if (dev->class) { - sysfs_remove_link(&dev->kobj, "subsystem"); - /* If this is not a "fake" compatible device, remove the - * symlink from the class to the device. */ - if (dev->kobj.parent != &dev->class->subsys.kobj) - sysfs_remove_link(&dev->class->subsys.kobj, - dev->bus_id); - if (parent) { -#ifdef CONFIG_SYSFS_DEPRECATED - char *class_name = make_class_name(dev->class->name, - &dev->kobj); - if (class_name) - sysfs_remove_link(&dev->parent->kobj, - class_name); - kfree(class_name); -#endif - sysfs_remove_link(&dev->kobj, "device"); - } - } ueventattrError: device_remove_file(dev, &uevent_attr); attrError: kobject_uevent(&dev->kobj, KOBJ_REMOVE); kobject_del(&dev->kobj); Error: + cleanup_device_parent(dev); if (parent) put_device(parent); goto Done; } - /** - * device_register - register a device with the system. - * @dev: pointer to the device structure + * device_register - register a device with the system. + * @dev: pointer to the device structure * - * This happens in two clean steps - initialize the device - * and add it to the system. The two steps can be called - * separately, but this is the easiest and most common. - * I.e. you should only call the two helpers separately if - * have a clearly defined need to use and refcount the device - * before it is added to the hierarchy. + * This happens in two clean steps - initialize the device + * and add it to the system. The two steps can be called + * separately, but this is the easiest and most common. + * I.e. you should only call the two helpers separately if + * have a clearly defined need to use and refcount the device + * before it is added to the hierarchy. */ - int device_register(struct device *dev) { device_initialize(dev); return device_add(dev); } - /** - * get_device - increment reference count for device. - * @dev: device. + * get_device - increment reference count for device. + * @dev: device. * - * This simply forwards the call to kobject_get(), though - * we do take care to provide for the case that we get a NULL - * pointer passed in. + * This simply forwards the call to kobject_get(), though + * we do take care to provide for the case that we get a NULL + * pointer passed in. */ - -struct device * get_device(struct device * dev) +struct device *get_device(struct device *dev) { return dev ? to_dev(kobject_get(&dev->kobj)) : NULL; } - /** - * put_device - decrement reference count. - * @dev: device in question. + * put_device - decrement reference count. + * @dev: device in question. */ -void put_device(struct device * dev) +void put_device(struct device *dev) { + /* might_sleep(); */ if (dev) kobject_put(&dev->kobj); } - /** - * device_del - delete device from system. - * @dev: device. + * device_del - delete device from system. + * @dev: device. * - * This is the first part of the device unregistration - * sequence. This removes the device from the lists we control - * from here, has it removed from the other driver model - * subsystems it was added to in device_add(), and removes it - * from the kobject hierarchy. + * This is the first part of the device unregistration + * sequence. This removes the device from the lists we control + * from here, has it removed from the other driver model + * subsystems it was added to in device_add(), and removes it + * from the kobject hierarchy. * - * NOTE: this should be called manually _iff_ device_add() was - * also called manually. + * NOTE: this should be called manually _iff_ device_add() was + * also called manually. */ - -void device_del(struct device * dev) +void device_del(struct device *dev) { - struct device * parent = dev->parent; + struct device *parent = dev->parent; struct class_interface *class_intf; + device_pm_remove(dev); if (parent) klist_del(&dev->knode_parent); if (MAJOR(dev->devt)) device_remove_file(dev, &devt_attr); if (dev->class) { - sysfs_remove_link(&dev->kobj, "subsystem"); - /* If this is not a "fake" compatible device, remove the - * symlink from the class to the device. */ - if (dev->kobj.parent != &dev->class->subsys.kobj) - sysfs_remove_link(&dev->class->subsys.kobj, - dev->bus_id); - if (parent) { -#ifdef CONFIG_SYSFS_DEPRECATED - char *class_name = make_class_name(dev->class->name, - &dev->kobj); - if (class_name) - sysfs_remove_link(&dev->parent->kobj, - class_name); - kfree(class_name); -#endif - sysfs_remove_link(&dev->kobj, "device"); - } + device_remove_class_symlinks(dev); down(&dev->class->sem); /* notify any interfaces that the device is now gone */ @@ -936,31 +941,6 @@ void device_del(struct device * dev) /* remove the device from the class list */ list_del_init(&dev->node); up(&dev->class->sem); - - /* If we live in a parent class-directory, unreference it */ - if (dev->kobj.parent->kset == &dev->class->class_dirs) { - struct device *d; - int other = 0; - - /* - * if we are the last child of our class, delete - * our class-directory at this parent - */ - down(&dev->class->sem); - list_for_each_entry(d, &dev->class->devices, node) { - if (d == dev) - continue; - if (d->kobj.parent == dev->kobj.parent) { - other = 1; - break; - } - } - if (!other) - kobject_del(dev->kobj.parent); - - kobject_put(dev->kobj.parent); - up(&dev->class->sem); - } } device_remove_file(dev, &uevent_attr); device_remove_attrs(dev); @@ -979,57 +959,55 @@ void device_del(struct device * dev) if (platform_notify_remove) platform_notify_remove(dev); if (dev->bus) - blocking_notifier_call_chain(&dev->bus->bus_notifier, + blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_DEL_DEVICE, dev); - device_pm_remove(dev); kobject_uevent(&dev->kobj, KOBJ_REMOVE); + cleanup_device_parent(dev); kobject_del(&dev->kobj); - if (parent) - put_device(parent); + put_device(parent); } /** - * device_unregister - unregister device from system. - * @dev: device going away. + * device_unregister - unregister device from system. + * @dev: device going away. * - * We do this in two parts, like we do device_register(). First, - * we remove it from all the subsystems with device_del(), then - * we decrement the reference count via put_device(). If that - * is the final reference count, the device will be cleaned up - * via device_release() above. Otherwise, the structure will - * stick around until the final reference to the device is dropped. + * We do this in two parts, like we do device_register(). First, + * we remove it from all the subsystems with device_del(), then + * we decrement the reference count via put_device(). If that + * is the final reference count, the device will be cleaned up + * via device_release() above. Otherwise, the structure will + * stick around until the final reference to the device is dropped. */ -void device_unregister(struct device * dev) +void device_unregister(struct device *dev) { - pr_debug("DEV: Unregistering device. ID = '%s'\n", dev->bus_id); + pr_debug("device: '%s': %s\n", dev->bus_id, __FUNCTION__); device_del(dev); put_device(dev); } - -static struct device * next_device(struct klist_iter * i) +static struct device *next_device(struct klist_iter *i) { - struct klist_node * n = klist_next(i); + struct klist_node *n = klist_next(i); return n ? container_of(n, struct device, knode_parent) : NULL; } /** - * device_for_each_child - device child iterator. - * @parent: parent struct device. - * @data: data for the callback. - * @fn: function to be called for each device. + * device_for_each_child - device child iterator. + * @parent: parent struct device. + * @data: data for the callback. + * @fn: function to be called for each device. * - * Iterate over @parent's child devices, and call @fn for each, - * passing it @data. + * Iterate over @parent's child devices, and call @fn for each, + * passing it @data. * - * We check the return of @fn each time. If it returns anything - * other than 0, we break out and return that value. + * We check the return of @fn each time. If it returns anything + * other than 0, we break out and return that value. */ -int device_for_each_child(struct device * parent, void * data, - int (*fn)(struct device *, void *)) +int device_for_each_child(struct device *parent, void *data, + int (*fn)(struct device *dev, void *data)) { struct klist_iter i; - struct device * child; + struct device *child; int error = 0; klist_iter_init(&parent->klist_children, &i); @@ -1054,8 +1032,8 @@ int device_for_each_child(struct device * parent, void * data, * current device can be obtained, this function will return to the caller * and not iterate over any more devices. */ -struct device * device_find_child(struct device *parent, void *data, - int (*match)(struct device *, void *)) +struct device *device_find_child(struct device *parent, void *data, + int (*match)(struct device *dev, void *data)) { struct klist_iter i; struct device *child; @@ -1073,7 +1051,10 @@ struct device * device_find_child(struct device *parent, void *data, int __init devices_init(void) { - return subsystem_register(&devices_subsys); + devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL); + if (!devices_kset) + return -ENOMEM; + return 0; } EXPORT_SYMBOL_GPL(device_for_each_child); @@ -1094,7 +1075,7 @@ EXPORT_SYMBOL_GPL(device_remove_file); static void device_create_release(struct device *dev) { - pr_debug("%s called for %s\n", __FUNCTION__, dev->bus_id); + pr_debug("device: '%s': %s\n", dev->bus_id, __FUNCTION__); kfree(dev); } @@ -1156,14 +1137,11 @@ struct device *device_create(struct class *class, struct device *parent, EXPORT_SYMBOL_GPL(device_create); /** - * device_destroy - removes a device that was created with device_create() + * find_device - finds a device that was created with device_create() * @class: pointer to the struct class that this device was registered with * @devt: the dev_t of the device that was previously registered - * - * This call unregisters and cleans up a device that was created with a - * call to device_create(). */ -void device_destroy(struct class *class, dev_t devt) +static struct device *find_device(struct class *class, dev_t devt) { struct device *dev = NULL; struct device *dev_tmp; @@ -1176,12 +1154,54 @@ void device_destroy(struct class *class, dev_t devt) } } up(&class->sem); + return dev; +} + +/** + * device_destroy - removes a device that was created with device_create() + * @class: pointer to the struct class that this device was registered with + * @devt: the dev_t of the device that was previously registered + * + * This call unregisters and cleans up a device that was created with a + * call to device_create(). + */ +void device_destroy(struct class *class, dev_t devt) +{ + struct device *dev; + dev = find_device(class, devt); if (dev) device_unregister(dev); } EXPORT_SYMBOL_GPL(device_destroy); +#ifdef CONFIG_PM_SLEEP +/** + * destroy_suspended_device - asks the PM core to remove a suspended device + * @class: pointer to the struct class that this device was registered with + * @devt: the dev_t of the device that was previously registered + * + * This call notifies the PM core of the necessity to unregister a suspended + * device created with a call to device_create() (devices cannot be + * unregistered directly while suspended, since the PM core holds their + * semaphores at that time). + * + * It can only be called within the scope of a system sleep transition. In + * practice this means it has to be directly or indirectly invoked either by + * a suspend or resume method, or by the PM core (e.g. via + * disable_nonboot_cpus() or enable_nonboot_cpus()). + */ +void destroy_suspended_device(struct class *class, dev_t devt) +{ + struct device *dev; + + dev = find_device(class, devt); + if (dev) + device_pm_schedule_removal(dev); +} +EXPORT_SYMBOL_GPL(destroy_suspended_device); +#endif /* CONFIG_PM_SLEEP */ + /** * device_rename - renames a device * @dev: the pointer to the struct device to be renamed @@ -1198,7 +1218,8 @@ int device_rename(struct device *dev, char *new_name) if (!dev) return -EINVAL; - pr_debug("DEVICE: renaming '%s' to '%s'\n", dev->bus_id, new_name); + pr_debug("device: '%s': %s: renaming to '%s'\n", dev->bus_id, + __FUNCTION__, new_name); #ifdef CONFIG_SYSFS_DEPRECATED if ((dev->class) && (dev->parent)) @@ -1279,8 +1300,7 @@ static int device_move_class_links(struct device *dev, class_name); if (error) sysfs_remove_link(&dev->kobj, "device"); - } - else + } else error = 0; out: kfree(class_name); @@ -1311,16 +1331,13 @@ int device_move(struct device *dev, struct device *new_parent) return -EINVAL; new_parent = get_device(new_parent); - new_parent_kobj = get_device_parent (dev, new_parent); - if (IS_ERR(new_parent_kobj)) { - error = PTR_ERR(new_parent_kobj); - put_device(new_parent); - goto out; - } - pr_debug("DEVICE: moving '%s' to '%s'\n", dev->bus_id, - new_parent ? new_parent->bus_id : "<NULL>"); + new_parent_kobj = get_device_parent(dev, new_parent); + + pr_debug("device: '%s': %s: moving to '%s'\n", dev->bus_id, + __FUNCTION__, new_parent ? new_parent->bus_id : "<NULL>"); error = kobject_move(&dev->kobj, new_parent_kobj); if (error) { + cleanup_glue_dir(dev, new_parent_kobj); put_device(new_parent); goto out; } @@ -1343,6 +1360,7 @@ int device_move(struct device *dev, struct device *new_parent) klist_add_tail(&dev->knode_parent, &old_parent->klist_children); } + cleanup_glue_dir(dev, new_parent_kobj); put_device(new_parent); goto out; } @@ -1352,5 +1370,23 @@ int device_move(struct device *dev, struct device *new_parent) put_device(dev); return error; } - EXPORT_SYMBOL_GPL(device_move); + +/** + * device_shutdown - call ->shutdown() on each device to shutdown. + */ +void device_shutdown(void) +{ + struct device *dev, *devn; + + list_for_each_entry_safe_reverse(dev, devn, &devices_kset->list, + kobj.entry) { + if (dev->bus && dev->bus->shutdown) { + dev_dbg(dev, "shutdown\n"); + dev->bus->shutdown(dev); + } else if (dev->driver && dev->driver->shutdown) { + dev_dbg(dev, "shutdown\n"); + dev->driver->shutdown(dev); + } + } +} diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 40545071e3c93adc625bb51cb87e007333f06417..c5885f5ce0ac9bc44b8bfdb37068360305133ed0 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -14,7 +14,7 @@ #include "base.h" struct sysdev_class cpu_sysdev_class = { - set_kset_name("cpu"), + .name = "cpu", }; EXPORT_SYMBOL(cpu_sysdev_class); diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 7ac474db88c525f46a0846810ca5f384fa07b104..a5cde94bb982aacc2b111e0c65773d8be8378351 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -1,18 +1,20 @@ /* - * drivers/base/dd.c - The core device/driver interactions. + * drivers/base/dd.c - The core device/driver interactions. * - * This file contains the (sometimes tricky) code that controls the - * interactions between devices and drivers, which primarily includes - * driver binding and unbinding. + * This file contains the (sometimes tricky) code that controls the + * interactions between devices and drivers, which primarily includes + * driver binding and unbinding. * - * All of this code used to exist in drivers/base/bus.c, but was - * relocated to here in the name of compartmentalization (since it wasn't - * strictly code just for the 'struct bus_type'. + * All of this code used to exist in drivers/base/bus.c, but was + * relocated to here in the name of compartmentalization (since it wasn't + * strictly code just for the 'struct bus_type'. * - * Copyright (c) 2002-5 Patrick Mochel - * Copyright (c) 2002-3 Open Source Development Labs + * Copyright (c) 2002-5 Patrick Mochel + * Copyright (c) 2002-3 Open Source Development Labs + * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de> + * Copyright (c) 2007 Novell Inc. * - * This file is released under the GPLv2 + * This file is released under the GPLv2 */ #include <linux/device.h> @@ -23,8 +25,6 @@ #include "base.h" #include "power/power.h" -#define to_drv(node) container_of(node, struct device_driver, kobj.entry) - static void driver_bound(struct device *dev) { @@ -34,27 +34,27 @@ static void driver_bound(struct device *dev) return; } - pr_debug("bound device '%s' to driver '%s'\n", - dev->bus_id, dev->driver->name); + pr_debug("driver: '%s': %s: bound to device '%s'\n", dev->bus_id, + __FUNCTION__, dev->driver->name); if (dev->bus) - blocking_notifier_call_chain(&dev->bus->bus_notifier, + blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_BOUND_DRIVER, dev); - klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices); + klist_add_tail(&dev->knode_driver, &dev->driver->p->klist_devices); } static int driver_sysfs_add(struct device *dev) { int ret; - ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj, + ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj, kobject_name(&dev->kobj)); if (ret == 0) { - ret = sysfs_create_link(&dev->kobj, &dev->driver->kobj, + ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj, "driver"); if (ret) - sysfs_remove_link(&dev->driver->kobj, + sysfs_remove_link(&dev->driver->p->kobj, kobject_name(&dev->kobj)); } return ret; @@ -65,24 +65,24 @@ static void driver_sysfs_remove(struct device *dev) struct device_driver *drv = dev->driver; if (drv) { - sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); + sysfs_remove_link(&drv->p->kobj, kobject_name(&dev->kobj)); sysfs_remove_link(&dev->kobj, "driver"); } } /** - * device_bind_driver - bind a driver to one device. - * @dev: device. + * device_bind_driver - bind a driver to one device. + * @dev: device. * - * Allow manual attachment of a driver to a device. - * Caller must have already set @dev->driver. + * Allow manual attachment of a driver to a device. + * Caller must have already set @dev->driver. * - * Note that this does not modify the bus reference count - * nor take the bus's rwsem. Please verify those are accounted - * for before calling this. (It is ok to call with no other effort - * from a driver's probe() method.) + * Note that this does not modify the bus reference count + * nor take the bus's rwsem. Please verify those are accounted + * for before calling this. (It is ok to call with no other effort + * from a driver's probe() method.) * - * This function must be called with @dev->sem held. + * This function must be called with @dev->sem held. */ int device_bind_driver(struct device *dev) { @@ -93,6 +93,7 @@ int device_bind_driver(struct device *dev) driver_bound(dev); return ret; } +EXPORT_SYMBOL_GPL(device_bind_driver); static atomic_t probe_count = ATOMIC_INIT(0); static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue); @@ -102,8 +103,8 @@ static int really_probe(struct device *dev, struct device_driver *drv) int ret = 0; atomic_inc(&probe_count); - pr_debug("%s: Probing driver %s with device %s\n", - drv->bus->name, drv->name, dev->bus_id); + pr_debug("bus: '%s': %s: probing driver %s with device %s\n", + drv->bus->name, __FUNCTION__, drv->name, dev->bus_id); WARN_ON(!list_empty(&dev->devres_head)); dev->driver = drv; @@ -125,8 +126,8 @@ static int really_probe(struct device *dev, struct device_driver *drv) driver_bound(dev); ret = 1; - pr_debug("%s: Bound Device %s to Driver %s\n", - drv->bus->name, dev->bus_id, drv->name); + pr_debug("bus: '%s': %s: bound device %s to driver %s\n", + drv->bus->name, __FUNCTION__, dev->bus_id, drv->name); goto done; probe_failed: @@ -183,7 +184,7 @@ int driver_probe_done(void) * This function must be called with @dev->sem held. When called for a * USB interface, @dev->parent->sem must be held as well. */ -int driver_probe_device(struct device_driver * drv, struct device * dev) +int driver_probe_device(struct device_driver *drv, struct device *dev) { int ret = 0; @@ -192,8 +193,8 @@ int driver_probe_device(struct device_driver * drv, struct device * dev) if (drv->bus->match && !drv->bus->match(dev, drv)) goto done; - pr_debug("%s: Matched Device %s with Driver %s\n", - drv->bus->name, dev->bus_id, drv->name); + pr_debug("bus: '%s': %s: matched device %s with driver %s\n", + drv->bus->name, __FUNCTION__, dev->bus_id, drv->name); ret = really_probe(dev, drv); @@ -201,27 +202,27 @@ int driver_probe_device(struct device_driver * drv, struct device * dev) return ret; } -static int __device_attach(struct device_driver * drv, void * data) +static int __device_attach(struct device_driver *drv, void *data) { - struct device * dev = data; + struct device *dev = data; return driver_probe_device(drv, dev); } /** - * device_attach - try to attach device to a driver. - * @dev: device. + * device_attach - try to attach device to a driver. + * @dev: device. * - * Walk the list of drivers that the bus has and call - * driver_probe_device() for each pair. If a compatible - * pair is found, break out and return. + * Walk the list of drivers that the bus has and call + * driver_probe_device() for each pair. If a compatible + * pair is found, break out and return. * - * Returns 1 if the device was bound to a driver; - * 0 if no matching device was found; - * -ENODEV if the device is not registered. + * Returns 1 if the device was bound to a driver; + * 0 if no matching device was found; + * -ENODEV if the device is not registered. * - * When called for a USB interface, @dev->parent->sem must be held. + * When called for a USB interface, @dev->parent->sem must be held. */ -int device_attach(struct device * dev) +int device_attach(struct device *dev) { int ret = 0; @@ -240,10 +241,11 @@ int device_attach(struct device * dev) up(&dev->sem); return ret; } +EXPORT_SYMBOL_GPL(device_attach); -static int __driver_attach(struct device * dev, void * data) +static int __driver_attach(struct device *dev, void *data) { - struct device_driver * drv = data; + struct device_driver *drv = data; /* * Lock device and try to bind to it. We drop the error @@ -268,35 +270,35 @@ static int __driver_attach(struct device * dev, void * data) } /** - * driver_attach - try to bind driver to devices. - * @drv: driver. + * driver_attach - try to bind driver to devices. + * @drv: driver. * - * Walk the list of devices that the bus has on it and try to - * match the driver with each one. If driver_probe_device() - * returns 0 and the @dev->driver is set, we've found a - * compatible pair. + * Walk the list of devices that the bus has on it and try to + * match the driver with each one. If driver_probe_device() + * returns 0 and the @dev->driver is set, we've found a + * compatible pair. */ -int driver_attach(struct device_driver * drv) +int driver_attach(struct device_driver *drv) { return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); } +EXPORT_SYMBOL_GPL(driver_attach); /* - * __device_release_driver() must be called with @dev->sem held. - * When called for a USB interface, @dev->parent->sem must be held as well. + * __device_release_driver() must be called with @dev->sem held. + * When called for a USB interface, @dev->parent->sem must be held as well. */ -static void __device_release_driver(struct device * dev) +static void __device_release_driver(struct device *dev) { - struct device_driver * drv; + struct device_driver *drv; - drv = get_driver(dev->driver); + drv = dev->driver; if (drv) { driver_sysfs_remove(dev); sysfs_remove_link(&dev->kobj, "driver"); - klist_remove(&dev->knode_driver); if (dev->bus) - blocking_notifier_call_chain(&dev->bus->bus_notifier, + blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_UNBIND_DRIVER, dev); @@ -306,18 +308,18 @@ static void __device_release_driver(struct device * dev) drv->remove(dev); devres_release_all(dev); dev->driver = NULL; - put_driver(drv); + klist_remove(&dev->knode_driver); } } /** - * device_release_driver - manually detach device from driver. - * @dev: device. + * device_release_driver - manually detach device from driver. + * @dev: device. * - * Manually detach device from driver. - * When called for a USB interface, @dev->parent->sem must be held. + * Manually detach device from driver. + * When called for a USB interface, @dev->parent->sem must be held. */ -void device_release_driver(struct device * dev) +void device_release_driver(struct device *dev) { /* * If anyone calls device_release_driver() recursively from @@ -328,26 +330,26 @@ void device_release_driver(struct device * dev) __device_release_driver(dev); up(&dev->sem); } - +EXPORT_SYMBOL_GPL(device_release_driver); /** * driver_detach - detach driver from all devices it controls. * @drv: driver. */ -void driver_detach(struct device_driver * drv) +void driver_detach(struct device_driver *drv) { - struct device * dev; + struct device *dev; for (;;) { - spin_lock(&drv->klist_devices.k_lock); - if (list_empty(&drv->klist_devices.k_list)) { - spin_unlock(&drv->klist_devices.k_lock); + spin_lock(&drv->p->klist_devices.k_lock); + if (list_empty(&drv->p->klist_devices.k_list)) { + spin_unlock(&drv->p->klist_devices.k_lock); break; } - dev = list_entry(drv->klist_devices.k_list.prev, + dev = list_entry(drv->p->klist_devices.k_list.prev, struct device, knode_driver.n_node); get_device(dev); - spin_unlock(&drv->klist_devices.k_lock); + spin_unlock(&drv->p->klist_devices.k_lock); if (dev->parent) /* Needed for USB */ down(&dev->parent->sem); @@ -360,9 +362,3 @@ void driver_detach(struct device_driver * drv) put_device(dev); } } - -EXPORT_SYMBOL_GPL(device_bind_driver); -EXPORT_SYMBOL_GPL(device_release_driver); -EXPORT_SYMBOL_GPL(device_attach); -EXPORT_SYMBOL_GPL(driver_attach); - diff --git a/drivers/base/driver.c b/drivers/base/driver.c index eb11475293ed614ea381589296db607381099cc2..a35f04121a00f938503f3b585c4e792e8a578d8f 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -3,6 +3,8 @@ * * Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs + * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de> + * Copyright (c) 2007 Novell Inc. * * This file is released under the GPLv2 * @@ -15,46 +17,42 @@ #include "base.h" #define to_dev(node) container_of(node, struct device, driver_list) -#define to_drv(obj) container_of(obj, struct device_driver, kobj) -static struct device * next_device(struct klist_iter * i) +static struct device *next_device(struct klist_iter *i) { - struct klist_node * n = klist_next(i); + struct klist_node *n = klist_next(i); return n ? container_of(n, struct device, knode_driver) : NULL; } /** - * driver_for_each_device - Iterator for devices bound to a driver. - * @drv: Driver we're iterating. - * @start: Device to begin with - * @data: Data to pass to the callback. - * @fn: Function to call for each device. + * driver_for_each_device - Iterator for devices bound to a driver. + * @drv: Driver we're iterating. + * @start: Device to begin with + * @data: Data to pass to the callback. + * @fn: Function to call for each device. * - * Iterate over the @drv's list of devices calling @fn for each one. + * Iterate over the @drv's list of devices calling @fn for each one. */ - -int driver_for_each_device(struct device_driver * drv, struct device * start, - void * data, int (*fn)(struct device *, void *)) +int driver_for_each_device(struct device_driver *drv, struct device *start, + void *data, int (*fn)(struct device *, void *)) { struct klist_iter i; - struct device * dev; + struct device *dev; int error = 0; if (!drv) return -EINVAL; - klist_iter_init_node(&drv->klist_devices, &i, + klist_iter_init_node(&drv->p->klist_devices, &i, start ? &start->knode_driver : NULL); while ((dev = next_device(&i)) && !error) error = fn(dev, data); klist_iter_exit(&i); return error; } - EXPORT_SYMBOL_GPL(driver_for_each_device); - /** * driver_find_device - device iterator for locating a particular device. * @drv: The device's driver @@ -70,9 +68,9 @@ EXPORT_SYMBOL_GPL(driver_for_each_device); * if it does. If the callback returns non-zero, this function will * return to the caller and not iterate over any more devices. */ -struct device * driver_find_device(struct device_driver *drv, - struct device * start, void * data, - int (*match)(struct device *, void *)) +struct device *driver_find_device(struct device_driver *drv, + struct device *start, void *data, + int (*match)(struct device *dev, void *data)) { struct klist_iter i; struct device *dev; @@ -80,7 +78,7 @@ struct device * driver_find_device(struct device_driver *drv, if (!drv) return NULL; - klist_iter_init_node(&drv->klist_devices, &i, + klist_iter_init_node(&drv->p->klist_devices, &i, (start ? &start->knode_driver : NULL)); while ((dev = next_device(&i))) if (match(dev, data) && get_device(dev)) @@ -91,111 +89,179 @@ struct device * driver_find_device(struct device_driver *drv, EXPORT_SYMBOL_GPL(driver_find_device); /** - * driver_create_file - create sysfs file for driver. - * @drv: driver. - * @attr: driver attribute descriptor. + * driver_create_file - create sysfs file for driver. + * @drv: driver. + * @attr: driver attribute descriptor. */ - -int driver_create_file(struct device_driver * drv, struct driver_attribute * attr) +int driver_create_file(struct device_driver *drv, + struct driver_attribute *attr) { int error; if (get_driver(drv)) { - error = sysfs_create_file(&drv->kobj, &attr->attr); + error = sysfs_create_file(&drv->p->kobj, &attr->attr); put_driver(drv); } else error = -EINVAL; return error; } - +EXPORT_SYMBOL_GPL(driver_create_file); /** - * driver_remove_file - remove sysfs file for driver. - * @drv: driver. - * @attr: driver attribute descriptor. + * driver_remove_file - remove sysfs file for driver. + * @drv: driver. + * @attr: driver attribute descriptor. */ - -void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr) +void driver_remove_file(struct device_driver *drv, + struct driver_attribute *attr) { if (get_driver(drv)) { - sysfs_remove_file(&drv->kobj, &attr->attr); + sysfs_remove_file(&drv->p->kobj, &attr->attr); put_driver(drv); } } - +EXPORT_SYMBOL_GPL(driver_remove_file); /** - * get_driver - increment driver reference count. - * @drv: driver. + * driver_add_kobj - add a kobject below the specified driver + * + * You really don't want to do this, this is only here due to one looney + * iseries driver, go poke those developers if you are annoyed about + * this... */ -struct device_driver * get_driver(struct device_driver * drv) +int driver_add_kobj(struct device_driver *drv, struct kobject *kobj, + const char *fmt, ...) { - return drv ? to_drv(kobject_get(&drv->kobj)) : NULL; + va_list args; + char *name; + + va_start(args, fmt); + name = kvasprintf(GFP_KERNEL, fmt, args); + va_end(args); + + if (!name) + return -ENOMEM; + + return kobject_add(kobj, &drv->p->kobj, "%s", name); } +EXPORT_SYMBOL_GPL(driver_add_kobj); + +/** + * get_driver - increment driver reference count. + * @drv: driver. + */ +struct device_driver *get_driver(struct device_driver *drv) +{ + if (drv) { + struct driver_private *priv; + struct kobject *kobj; + kobj = kobject_get(&drv->p->kobj); + priv = to_driver(kobj); + return priv->driver; + } + return NULL; +} +EXPORT_SYMBOL_GPL(get_driver); /** - * put_driver - decrement driver's refcount. - * @drv: driver. + * put_driver - decrement driver's refcount. + * @drv: driver. */ -void put_driver(struct device_driver * drv) +void put_driver(struct device_driver *drv) +{ + kobject_put(&drv->p->kobj); +} +EXPORT_SYMBOL_GPL(put_driver); + +static int driver_add_groups(struct device_driver *drv, + struct attribute_group **groups) { - kobject_put(&drv->kobj); + int error = 0; + int i; + + if (groups) { + for (i = 0; groups[i]; i++) { + error = sysfs_create_group(&drv->p->kobj, groups[i]); + if (error) { + while (--i >= 0) + sysfs_remove_group(&drv->p->kobj, + groups[i]); + break; + } + } + } + return error; +} + +static void driver_remove_groups(struct device_driver *drv, + struct attribute_group **groups) +{ + int i; + + if (groups) + for (i = 0; groups[i]; i++) + sysfs_remove_group(&drv->p->kobj, groups[i]); } /** - * driver_register - register driver with bus - * @drv: driver to register + * driver_register - register driver with bus + * @drv: driver to register * - * We pass off most of the work to the bus_add_driver() call, - * since most of the things we have to do deal with the bus - * structures. + * We pass off most of the work to the bus_add_driver() call, + * since most of the things we have to do deal with the bus + * structures. */ -int driver_register(struct device_driver * drv) +int driver_register(struct device_driver *drv) { + int ret; + if ((drv->bus->probe && drv->probe) || (drv->bus->remove && drv->remove) || - (drv->bus->shutdown && drv->shutdown)) { - printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name); - } - klist_init(&drv->klist_devices, NULL, NULL); - return bus_add_driver(drv); + (drv->bus->shutdown && drv->shutdown)) + printk(KERN_WARNING "Driver '%s' needs updating - please use " + "bus_type methods\n", drv->name); + ret = bus_add_driver(drv); + if (ret) + return ret; + ret = driver_add_groups(drv, drv->groups); + if (ret) + bus_remove_driver(drv); + return ret; } +EXPORT_SYMBOL_GPL(driver_register); /** - * driver_unregister - remove driver from system. - * @drv: driver. + * driver_unregister - remove driver from system. + * @drv: driver. * - * Again, we pass off most of the work to the bus-level call. + * Again, we pass off most of the work to the bus-level call. */ - -void driver_unregister(struct device_driver * drv) +void driver_unregister(struct device_driver *drv) { + driver_remove_groups(drv, drv->groups); bus_remove_driver(drv); } +EXPORT_SYMBOL_GPL(driver_unregister); /** - * driver_find - locate driver on a bus by its name. - * @name: name of the driver. - * @bus: bus to scan for the driver. + * driver_find - locate driver on a bus by its name. + * @name: name of the driver. + * @bus: bus to scan for the driver. * - * Call kset_find_obj() to iterate over list of drivers on - * a bus to find driver by name. Return driver if found. + * Call kset_find_obj() to iterate over list of drivers on + * a bus to find driver by name. Return driver if found. * - * Note that kset_find_obj increments driver's reference count. + * Note that kset_find_obj increments driver's reference count. */ struct device_driver *driver_find(const char *name, struct bus_type *bus) { - struct kobject *k = kset_find_obj(&bus->drivers, name); - if (k) - return to_drv(k); + struct kobject *k = kset_find_obj(bus->p->drivers_kset, name); + struct driver_private *priv; + + if (k) { + priv = to_driver(k); + return priv->driver; + } return NULL; } - -EXPORT_SYMBOL_GPL(driver_register); -EXPORT_SYMBOL_GPL(driver_unregister); -EXPORT_SYMBOL_GPL(get_driver); -EXPORT_SYMBOL_GPL(put_driver); EXPORT_SYMBOL_GPL(driver_find); - -EXPORT_SYMBOL_GPL(driver_create_file); -EXPORT_SYMBOL_GPL(driver_remove_file); diff --git a/drivers/base/firmware.c b/drivers/base/firmware.c index 90c8629321698b8a697d84b47f04eb67ded96b89..11381555680943616bbc82a734f4e0e860ee5024 100644 --- a/drivers/base/firmware.c +++ b/drivers/base/firmware.c @@ -3,11 +3,11 @@ * * Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs + * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de> + * Copyright (c) 2007 Novell Inc. * * This file is released under the GPLv2 - * */ - #include <linux/kobject.h> #include <linux/module.h> #include <linux/init.h> @@ -15,23 +15,13 @@ #include "base.h" -static decl_subsys(firmware, NULL, NULL); - -int firmware_register(struct kset *s) -{ - kobj_set_kset_s(s, firmware_subsys); - return subsystem_register(s); -} - -void firmware_unregister(struct kset *s) -{ - subsystem_unregister(s); -} +struct kobject *firmware_kobj; +EXPORT_SYMBOL_GPL(firmware_kobj); int __init firmware_init(void) { - return subsystem_register(&firmware_subsys); + firmware_kobj = kobject_create_and_add("firmware", NULL); + if (!firmware_kobj) + return -ENOMEM; + return 0; } - -EXPORT_SYMBOL_GPL(firmware_register); -EXPORT_SYMBOL_GPL(firmware_unregister); diff --git a/drivers/base/hypervisor.c b/drivers/base/hypervisor.c index 7080b413ddc9f6c475056adf161cf248321c9927..6428cba3aadddf51081926671143504e5a9247e8 100644 --- a/drivers/base/hypervisor.c +++ b/drivers/base/hypervisor.c @@ -2,19 +2,23 @@ * hypervisor.c - /sys/hypervisor subsystem. * * Copyright (C) IBM Corp. 2006 + * Copyright (C) 2007 Greg Kroah-Hartman <gregkh@suse.de> + * Copyright (C) 2007 Novell Inc. * * This file is released under the GPLv2 */ #include <linux/kobject.h> #include <linux/device.h> - #include "base.h" -decl_subsys(hypervisor, NULL, NULL); -EXPORT_SYMBOL_GPL(hypervisor_subsys); +struct kobject *hypervisor_kobj; +EXPORT_SYMBOL_GPL(hypervisor_kobj); int __init hypervisor_init(void) { - return subsystem_register(&hypervisor_subsys); + hypervisor_kobj = kobject_create_and_add("hypervisor", NULL); + if (!hypervisor_kobj) + return -ENOMEM; + return 0; } diff --git a/drivers/base/init.c b/drivers/base/init.c index 37138154f9e824b353f322022ba8c41017ae3c3e..7bd9b6a5b01f9497fcb2c35fccae144860299f93 100644 --- a/drivers/base/init.c +++ b/drivers/base/init.c @@ -1,10 +1,8 @@ /* - * * Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs * * This file is released under the GPLv2 - * */ #include <linux/device.h> @@ -14,12 +12,11 @@ #include "base.h" /** - * driver_init - initialize driver model. + * driver_init - initialize driver model. * - * Call the driver model init functions to initialize their - * subsystems. Called early from init/main.c. + * Call the driver model init functions to initialize their + * subsystems. Called early from init/main.c. */ - void __init driver_init(void) { /* These are the core pieces */ @@ -36,5 +33,4 @@ void __init driver_init(void) system_bus_init(); cpu_dev_init(); memory_dev_init(); - attribute_container_init(); } diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 7868707c7eda30035ea2eff7e3309011c11a2669..7ae413fdd5fc4bd1f0d1b0941316df52dbe8e11f 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -26,7 +26,7 @@ #define MEMORY_CLASS_NAME "memory" static struct sysdev_class memory_sysdev_class = { - set_kset_name(MEMORY_CLASS_NAME), + .name = MEMORY_CLASS_NAME, }; static const char *memory_uevent_name(struct kset *kset, struct kobject *kobj) diff --git a/drivers/base/module.c b/drivers/base/module.c new file mode 100644 index 0000000000000000000000000000000000000000..103be9cacb050bc23364cb3718b2ea51734bfc21 --- /dev/null +++ b/drivers/base/module.c @@ -0,0 +1,94 @@ +/* + * module.c - module sysfs fun for drivers + * + * This file is released under the GPLv2 + * + */ +#include <linux/device.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/string.h> +#include "base.h" + +static char *make_driver_name(struct device_driver *drv) +{ + char *driver_name; + + driver_name = kmalloc(strlen(drv->name) + strlen(drv->bus->name) + 2, + GFP_KERNEL); + if (!driver_name) + return NULL; + + sprintf(driver_name, "%s:%s", drv->bus->name, drv->name); + return driver_name; +} + +static void module_create_drivers_dir(struct module_kobject *mk) +{ + if (!mk || mk->drivers_dir) + return; + + mk->drivers_dir = kobject_create_and_add("drivers", &mk->kobj); +} + +void module_add_driver(struct module *mod, struct device_driver *drv) +{ + char *driver_name; + int no_warn; + struct module_kobject *mk = NULL; + + if (!drv) + return; + + if (mod) + mk = &mod->mkobj; + else if (drv->mod_name) { + struct kobject *mkobj; + + /* Lookup built-in module entry in /sys/modules */ + mkobj = kset_find_obj(module_kset, drv->mod_name); + if (mkobj) { + mk = container_of(mkobj, struct module_kobject, kobj); + /* remember our module structure */ + drv->p->mkobj = mk; + /* kset_find_obj took a reference */ + kobject_put(mkobj); + } + } + + if (!mk) + return; + + /* Don't check return codes; these calls are idempotent */ + no_warn = sysfs_create_link(&drv->p->kobj, &mk->kobj, "module"); + driver_name = make_driver_name(drv); + if (driver_name) { + module_create_drivers_dir(mk); + no_warn = sysfs_create_link(mk->drivers_dir, &drv->p->kobj, + driver_name); + kfree(driver_name); + } +} + +void module_remove_driver(struct device_driver *drv) +{ + struct module_kobject *mk = NULL; + char *driver_name; + + if (!drv) + return; + + sysfs_remove_link(&drv->p->kobj, "module"); + + if (drv->owner) + mk = &drv->owner->mkobj; + else if (drv->p->mkobj) + mk = drv->p->mkobj; + if (mk && mk->drivers_dir) { + driver_name = make_driver_name(drv); + if (driver_name) { + sysfs_remove_link(mk->drivers_dir, driver_name); + kfree(driver_name); + } + } +} diff --git a/drivers/base/node.c b/drivers/base/node.c index 88eeed72b5d6557289392202a21338496676e55b..e59861f18ce55616981e7ca9fbc5ad2a6698f04f 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -15,7 +15,7 @@ #include <linux/device.h> static struct sysdev_class node_class = { - set_kset_name("node"), + .name = "node", }; diff --git a/drivers/base/platform.c b/drivers/base/platform.c index fb56092414821645342071f5c0da32ef2a486b4b..efaf282c438c4108b1f01c41dc6b873c0fde669d 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -20,7 +20,8 @@ #include "base.h" -#define to_platform_driver(drv) (container_of((drv), struct platform_driver, driver)) +#define to_platform_driver(drv) (container_of((drv), struct platform_driver, \ + driver)) struct device platform_bus = { .bus_id = "platform", @@ -28,14 +29,13 @@ struct device platform_bus = { EXPORT_SYMBOL_GPL(platform_bus); /** - * platform_get_resource - get a resource for a device - * @dev: platform device - * @type: resource type - * @num: resource index + * platform_get_resource - get a resource for a device + * @dev: platform device + * @type: resource type + * @num: resource index */ -struct resource * -platform_get_resource(struct platform_device *dev, unsigned int type, - unsigned int num) +struct resource *platform_get_resource(struct platform_device *dev, + unsigned int type, unsigned int num) { int i; @@ -43,8 +43,7 @@ platform_get_resource(struct platform_device *dev, unsigned int type, struct resource *r = &dev->resource[i]; if ((r->flags & (IORESOURCE_IO|IORESOURCE_MEM| - IORESOURCE_IRQ|IORESOURCE_DMA)) - == type) + IORESOURCE_IRQ|IORESOURCE_DMA)) == type) if (num-- == 0) return r; } @@ -53,9 +52,9 @@ platform_get_resource(struct platform_device *dev, unsigned int type, EXPORT_SYMBOL_GPL(platform_get_resource); /** - * platform_get_irq - get an IRQ for a device - * @dev: platform device - * @num: IRQ number index + * platform_get_irq - get an IRQ for a device + * @dev: platform device + * @num: IRQ number index */ int platform_get_irq(struct platform_device *dev, unsigned int num) { @@ -66,14 +65,13 @@ int platform_get_irq(struct platform_device *dev, unsigned int num) EXPORT_SYMBOL_GPL(platform_get_irq); /** - * platform_get_resource_byname - get a resource for a device by name - * @dev: platform device - * @type: resource type - * @name: resource name + * platform_get_resource_byname - get a resource for a device by name + * @dev: platform device + * @type: resource type + * @name: resource name */ -struct resource * -platform_get_resource_byname(struct platform_device *dev, unsigned int type, - char *name) +struct resource *platform_get_resource_byname(struct platform_device *dev, + unsigned int type, char *name) { int i; @@ -90,22 +88,23 @@ platform_get_resource_byname(struct platform_device *dev, unsigned int type, EXPORT_SYMBOL_GPL(platform_get_resource_byname); /** - * platform_get_irq - get an IRQ for a device - * @dev: platform device - * @name: IRQ name + * platform_get_irq - get an IRQ for a device + * @dev: platform device + * @name: IRQ name */ int platform_get_irq_byname(struct platform_device *dev, char *name) { - struct resource *r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name); + struct resource *r = platform_get_resource_byname(dev, IORESOURCE_IRQ, + name); return r ? r->start : -ENXIO; } EXPORT_SYMBOL_GPL(platform_get_irq_byname); /** - * platform_add_devices - add a numbers of platform devices - * @devs: array of platform devices to add - * @num: number of platform devices in array + * platform_add_devices - add a numbers of platform devices + * @devs: array of platform devices to add + * @num: number of platform devices in array */ int platform_add_devices(struct platform_device **devs, int num) { @@ -130,12 +129,11 @@ struct platform_object { }; /** - * platform_device_put - * @pdev: platform device to free + * platform_device_put + * @pdev: platform device to free * - * Free all memory associated with a platform device. This function - * must _only_ be externally called in error cases. All other usage - * is a bug. + * Free all memory associated with a platform device. This function must + * _only_ be externally called in error cases. All other usage is a bug. */ void platform_device_put(struct platform_device *pdev) { @@ -146,7 +144,8 @@ EXPORT_SYMBOL_GPL(platform_device_put); static void platform_device_release(struct device *dev) { - struct platform_object *pa = container_of(dev, struct platform_object, pdev.dev); + struct platform_object *pa = container_of(dev, struct platform_object, + pdev.dev); kfree(pa->pdev.dev.platform_data); kfree(pa->pdev.resource); @@ -154,12 +153,12 @@ static void platform_device_release(struct device *dev) } /** - * platform_device_alloc - * @name: base name of the device we're adding - * @id: instance id + * platform_device_alloc + * @name: base name of the device we're adding + * @id: instance id * - * Create a platform device object which can have other objects attached - * to it, and which will have attached objects freed when it is released. + * Create a platform device object which can have other objects attached + * to it, and which will have attached objects freed when it is released. */ struct platform_device *platform_device_alloc(const char *name, int id) { @@ -179,16 +178,17 @@ struct platform_device *platform_device_alloc(const char *name, int id) EXPORT_SYMBOL_GPL(platform_device_alloc); /** - * platform_device_add_resources - * @pdev: platform device allocated by platform_device_alloc to add resources to - * @res: set of resources that needs to be allocated for the device - * @num: number of resources + * platform_device_add_resources + * @pdev: platform device allocated by platform_device_alloc to add resources to + * @res: set of resources that needs to be allocated for the device + * @num: number of resources * - * Add a copy of the resources to the platform device. The memory - * associated with the resources will be freed when the platform - * device is released. + * Add a copy of the resources to the platform device. The memory + * associated with the resources will be freed when the platform device is + * released. */ -int platform_device_add_resources(struct platform_device *pdev, struct resource *res, unsigned int num) +int platform_device_add_resources(struct platform_device *pdev, + struct resource *res, unsigned int num) { struct resource *r; @@ -203,16 +203,17 @@ int platform_device_add_resources(struct platform_device *pdev, struct resource EXPORT_SYMBOL_GPL(platform_device_add_resources); /** - * platform_device_add_data - * @pdev: platform device allocated by platform_device_alloc to add resources to - * @data: platform specific data for this platform device - * @size: size of platform specific data + * platform_device_add_data + * @pdev: platform device allocated by platform_device_alloc to add resources to + * @data: platform specific data for this platform device + * @size: size of platform specific data * - * Add a copy of platform specific data to the platform device's platform_data - * pointer. The memory associated with the platform data will be freed - * when the platform device is released. + * Add a copy of platform specific data to the platform device's + * platform_data pointer. The memory associated with the platform data + * will be freed when the platform device is released. */ -int platform_device_add_data(struct platform_device *pdev, const void *data, size_t size) +int platform_device_add_data(struct platform_device *pdev, const void *data, + size_t size) { void *d; @@ -226,11 +227,11 @@ int platform_device_add_data(struct platform_device *pdev, const void *data, siz EXPORT_SYMBOL_GPL(platform_device_add_data); /** - * platform_device_add - add a platform device to device hierarchy - * @pdev: platform device we're adding + * platform_device_add - add a platform device to device hierarchy + * @pdev: platform device we're adding * - * This is part 2 of platform_device_register(), though may be called - * separately _iff_ pdev was allocated by platform_device_alloc(). + * This is part 2 of platform_device_register(), though may be called + * separately _iff_ pdev was allocated by platform_device_alloc(). */ int platform_device_add(struct platform_device *pdev) { @@ -289,13 +290,12 @@ int platform_device_add(struct platform_device *pdev) EXPORT_SYMBOL_GPL(platform_device_add); /** - * platform_device_del - remove a platform-level device - * @pdev: platform device we're removing + * platform_device_del - remove a platform-level device + * @pdev: platform device we're removing * - * Note that this function will also release all memory- and port-based - * resources owned by the device (@dev->resource). This function - * must _only_ be externally called in error cases. All other usage - * is a bug. + * Note that this function will also release all memory- and port-based + * resources owned by the device (@dev->resource). This function must + * _only_ be externally called in error cases. All other usage is a bug. */ void platform_device_del(struct platform_device *pdev) { @@ -314,11 +314,10 @@ void platform_device_del(struct platform_device *pdev) EXPORT_SYMBOL_GPL(platform_device_del); /** - * platform_device_register - add a platform-level device - * @pdev: platform device we're adding - * + * platform_device_register - add a platform-level device + * @pdev: platform device we're adding */ -int platform_device_register(struct platform_device * pdev) +int platform_device_register(struct platform_device *pdev) { device_initialize(&pdev->dev); return platform_device_add(pdev); @@ -326,14 +325,14 @@ int platform_device_register(struct platform_device * pdev) EXPORT_SYMBOL_GPL(platform_device_register); /** - * platform_device_unregister - unregister a platform-level device - * @pdev: platform device we're unregistering + * platform_device_unregister - unregister a platform-level device + * @pdev: platform device we're unregistering * - * Unregistration is done in 2 steps. First we release all resources - * and remove it from the subsystem, then we drop reference count by - * calling platform_device_put(). + * Unregistration is done in 2 steps. First we release all resources + * and remove it from the subsystem, then we drop reference count by + * calling platform_device_put(). */ -void platform_device_unregister(struct platform_device * pdev) +void platform_device_unregister(struct platform_device *pdev) { platform_device_del(pdev); platform_device_put(pdev); @@ -341,27 +340,29 @@ void platform_device_unregister(struct platform_device * pdev) EXPORT_SYMBOL_GPL(platform_device_unregister); /** - * platform_device_register_simple - * @name: base name of the device we're adding - * @id: instance id - * @res: set of resources that needs to be allocated for the device - * @num: number of resources + * platform_device_register_simple + * @name: base name of the device we're adding + * @id: instance id + * @res: set of resources that needs to be allocated for the device + * @num: number of resources * - * This function creates a simple platform device that requires minimal - * resource and memory management. Canned release function freeing - * memory allocated for the device allows drivers using such devices - * to be unloaded without waiting for the last reference to the device - * to be dropped. + * This function creates a simple platform device that requires minimal + * resource and memory management. Canned release function freeing memory + * allocated for the device allows drivers using such devices to be + * unloaded without waiting for the last reference to the device to be + * dropped. * - * This interface is primarily intended for use with legacy drivers - * which probe hardware directly. Because such drivers create sysfs - * device nodes themselves, rather than letting system infrastructure - * handle such device enumeration tasks, they don't fully conform to - * the Linux driver model. In particular, when such drivers are built - * as modules, they can't be "hotplugged". + * This interface is primarily intended for use with legacy drivers which + * probe hardware directly. Because such drivers create sysfs device nodes + * themselves, rather than letting system infrastructure handle such device + * enumeration tasks, they don't fully conform to the Linux driver model. + * In particular, when such drivers are built as modules, they can't be + * "hotplugged". */ -struct platform_device *platform_device_register_simple(char *name, int id, - struct resource *res, unsigned int num) +struct platform_device *platform_device_register_simple(const char *name, + int id, + struct resource *res, + unsigned int num) { struct platform_device *pdev; int retval; @@ -436,8 +437,8 @@ static int platform_drv_resume(struct device *_dev) } /** - * platform_driver_register - * @drv: platform driver structure + * platform_driver_register + * @drv: platform driver structure */ int platform_driver_register(struct platform_driver *drv) { @@ -457,8 +458,8 @@ int platform_driver_register(struct platform_driver *drv) EXPORT_SYMBOL_GPL(platform_driver_register); /** - * platform_driver_unregister - * @drv: platform driver structure + * platform_driver_unregister + * @drv: platform driver structure */ void platform_driver_unregister(struct platform_driver *drv) { @@ -497,12 +498,12 @@ int __init_or_module platform_driver_probe(struct platform_driver *drv, * if the probe was successful, and make sure any forced probes of * new devices fail. */ - spin_lock(&platform_bus_type.klist_drivers.k_lock); + spin_lock(&platform_bus_type.p->klist_drivers.k_lock); drv->probe = NULL; - if (code == 0 && list_empty(&drv->driver.klist_devices.k_list)) + if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list)) retval = -ENODEV; drv->driver.probe = platform_drv_probe_fail; - spin_unlock(&platform_bus_type.klist_drivers.k_lock); + spin_unlock(&platform_bus_type.p->klist_drivers.k_lock); if (code != retval) platform_driver_unregister(drv); @@ -516,8 +517,8 @@ EXPORT_SYMBOL_GPL(platform_driver_probe); * (b) sysfs attribute lets new-style coldplug recover from hotplug events * mishandled before system is fully running: "modprobe $(cat modalias)" */ -static ssize_t -modalias_show(struct device *dev, struct device_attribute *a, char *buf) +static ssize_t modalias_show(struct device *dev, struct device_attribute *a, + char *buf) { struct platform_device *pdev = to_platform_device(dev); int len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name); @@ -538,26 +539,24 @@ static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) return 0; } - /** - * platform_match - bind platform device to platform driver. - * @dev: device. - * @drv: driver. + * platform_match - bind platform device to platform driver. + * @dev: device. + * @drv: driver. * - * Platform device IDs are assumed to be encoded like this: - * "<name><instance>", where <name> is a short description of the - * type of device, like "pci" or "floppy", and <instance> is the - * enumerated instance of the device, like '0' or '42'. - * Driver IDs are simply "<name>". - * So, extract the <name> from the platform_device structure, - * and compare it against the name of the driver. Return whether - * they match or not. + * Platform device IDs are assumed to be encoded like this: + * "<name><instance>", where <name> is a short description of the type of + * device, like "pci" or "floppy", and <instance> is the enumerated + * instance of the device, like '0' or '42'. Driver IDs are simply + * "<name>". So, extract the <name> from the platform_device structure, + * and compare it against the name of the driver. Return whether they match + * or not. */ - -static int platform_match(struct device * dev, struct device_driver * drv) +static int platform_match(struct device *dev, struct device_driver *drv) { - struct platform_device *pdev = container_of(dev, struct platform_device, dev); + struct platform_device *pdev; + pdev = container_of(dev, struct platform_device, dev); return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0); } @@ -574,9 +573,10 @@ static int platform_suspend(struct device *dev, pm_message_t mesg) static int platform_suspend_late(struct device *dev, pm_message_t mesg) { struct platform_driver *drv = to_platform_driver(dev->driver); - struct platform_device *pdev = container_of(dev, struct platform_device, dev); + struct platform_device *pdev; int ret = 0; + pdev = container_of(dev, struct platform_device, dev); if (dev->driver && drv->suspend_late) ret = drv->suspend_late(pdev, mesg); @@ -586,16 +586,17 @@ static int platform_suspend_late(struct device *dev, pm_message_t mesg) static int platform_resume_early(struct device *dev) { struct platform_driver *drv = to_platform_driver(dev->driver); - struct platform_device *pdev = container_of(dev, struct platform_device, dev); + struct platform_device *pdev; int ret = 0; + pdev = container_of(dev, struct platform_device, dev); if (dev->driver && drv->resume_early) ret = drv->resume_early(pdev); return ret; } -static int platform_resume(struct device * dev) +static int platform_resume(struct device *dev) { int ret = 0; diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index 44504e6618fbb0006e369cf39ff75d55578057bb..06a86fe6a78d77a1c2d0a3b7e84003456c430933 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile @@ -1,4 +1,3 @@ -obj-y := shutdown.o obj-$(CONFIG_PM) += sysfs.o obj-$(CONFIG_PM_SLEEP) += main.o obj-$(CONFIG_PM_TRACE) += trace.o diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 691ffb64cc3724461fa3d877f3a8aae10dca96d9..200ed5fafd505ad0e18fff1131500e2a2fd4ba9c 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -24,20 +24,45 @@ #include <linux/mutex.h> #include <linux/pm.h> #include <linux/resume-trace.h> +#include <linux/rwsem.h> #include "../base.h" #include "power.h" +/* + * The entries in the dpm_active list are in a depth first order, simply + * because children are guaranteed to be discovered after parents, and + * are inserted at the back of the list on discovery. + * + * All the other lists are kept in the same order, for consistency. + * However the lists aren't always traversed in the same order. + * Semaphores must be acquired from the top (i.e., front) down + * and released in the opposite order. Devices must be suspended + * from the bottom (i.e., end) up and resumed in the opposite order. + * That way no parent will be suspended while it still has an active + * child. + * + * Since device_pm_add() may be called with a device semaphore held, + * we must never try to acquire a device semaphore while holding + * dpm_list_mutex. + */ + LIST_HEAD(dpm_active); +static LIST_HEAD(dpm_locked); static LIST_HEAD(dpm_off); static LIST_HEAD(dpm_off_irq); +static LIST_HEAD(dpm_destroy); -static DEFINE_MUTEX(dpm_mtx); static DEFINE_MUTEX(dpm_list_mtx); -int (*platform_enable_wakeup)(struct device *dev, int is_on); +static DECLARE_RWSEM(pm_sleep_rwsem); +int (*platform_enable_wakeup)(struct device *dev, int is_on); +/** + * device_pm_add - add a device to the list of active devices + * @dev: Device to be added to the list + */ void device_pm_add(struct device *dev) { pr_debug("PM: Adding info for %s:%s\n", @@ -48,8 +73,36 @@ void device_pm_add(struct device *dev) mutex_unlock(&dpm_list_mtx); } +/** + * device_pm_remove - remove a device from the list of active devices + * @dev: Device to be removed from the list + * + * This function also removes the device's PM-related sysfs attributes. + */ void device_pm_remove(struct device *dev) { + /* + * If this function is called during a suspend, it will be blocked, + * because we're holding the device's semaphore at that time, which may + * lead to a deadlock. In that case we want to print a warning. + * However, it may also be called by unregister_dropped_devices() with + * the device's semaphore released, in which case the warning should + * not be printed. + */ + if (down_trylock(&dev->sem)) { + if (down_read_trylock(&pm_sleep_rwsem)) { + /* No suspend in progress, wait on dev->sem */ + down(&dev->sem); + up_read(&pm_sleep_rwsem); + } else { + /* Suspend in progress, we may deadlock */ + dev_warn(dev, "Suspicious %s during suspend\n", + __FUNCTION__); + dump_stack(); + /* The user has been warned ... */ + down(&dev->sem); + } + } pr_debug("PM: Removing info for %s:%s\n", dev->bus ? dev->bus->name : "No Bus", kobject_name(&dev->kobj)); @@ -57,25 +110,124 @@ void device_pm_remove(struct device *dev) dpm_sysfs_remove(dev); list_del_init(&dev->power.entry); mutex_unlock(&dpm_list_mtx); + up(&dev->sem); +} + +/** + * device_pm_schedule_removal - schedule the removal of a suspended device + * @dev: Device to destroy + * + * Moves the device to the dpm_destroy list for further processing by + * unregister_dropped_devices(). + */ +void device_pm_schedule_removal(struct device *dev) +{ + pr_debug("PM: Preparing for removal: %s:%s\n", + dev->bus ? dev->bus->name : "No Bus", + kobject_name(&dev->kobj)); + mutex_lock(&dpm_list_mtx); + list_move_tail(&dev->power.entry, &dpm_destroy); + mutex_unlock(&dpm_list_mtx); +} + +/** + * pm_sleep_lock - mutual exclusion for registration and suspend + * + * Returns 0 if no suspend is underway and device registration + * may proceed, otherwise -EBUSY. + */ +int pm_sleep_lock(void) +{ + if (down_read_trylock(&pm_sleep_rwsem)) + return 0; + + return -EBUSY; +} + +/** + * pm_sleep_unlock - mutual exclusion for registration and suspend + * + * This routine undoes the effect of device_pm_add_lock + * when a device's registration is complete. + */ +void pm_sleep_unlock(void) +{ + up_read(&pm_sleep_rwsem); } /*------------------------- Resume routines -------------------------*/ /** - * resume_device - Restore state for one device. + * resume_device_early - Power on one device (early resume). * @dev: Device. * + * Must be called with interrupts disabled. */ - -static int resume_device(struct device * dev) +static int resume_device_early(struct device *dev) { int error = 0; TRACE_DEVICE(dev); TRACE_RESUME(0); - down(&dev->sem); + if (dev->bus && dev->bus->resume_early) { + dev_dbg(dev, "EARLY resume\n"); + error = dev->bus->resume_early(dev); + } + + TRACE_RESUME(error); + return error; +} + +/** + * dpm_power_up - Power on all regular (non-sysdev) devices. + * + * Walk the dpm_off_irq list and power each device up. This + * is used for devices that required they be powered down with + * interrupts disabled. As devices are powered on, they are moved + * to the dpm_off list. + * + * Must be called with interrupts disabled and only one CPU running. + */ +static void dpm_power_up(void) +{ + + while (!list_empty(&dpm_off_irq)) { + struct list_head *entry = dpm_off_irq.next; + struct device *dev = to_device(entry); + + list_move_tail(entry, &dpm_off); + resume_device_early(dev); + } +} + +/** + * device_power_up - Turn on all devices that need special attention. + * + * Power on system devices, then devices that required we shut them down + * with interrupts disabled. + * + * Must be called with interrupts disabled. + */ +void device_power_up(void) +{ + sysdev_resume(); + dpm_power_up(); +} +EXPORT_SYMBOL_GPL(device_power_up); + +/** + * resume_device - Restore state for one device. + * @dev: Device. + * + */ +static int resume_device(struct device *dev) +{ + int error = 0; + + TRACE_DEVICE(dev); + TRACE_RESUME(0); if (dev->bus && dev->bus->resume) { dev_dbg(dev,"resuming\n"); @@ -92,126 +244,94 @@ static int resume_device(struct device * dev) error = dev->class->resume(dev); } - up(&dev->sem); - TRACE_RESUME(error); return error; } - -static int resume_device_early(struct device * dev) -{ - int error = 0; - - TRACE_DEVICE(dev); - TRACE_RESUME(0); - if (dev->bus && dev->bus->resume_early) { - dev_dbg(dev,"EARLY resume\n"); - error = dev->bus->resume_early(dev); - } - TRACE_RESUME(error); - return error; -} - -/* - * Resume the devices that have either not gone through - * the late suspend, or that did go through it but also - * went through the early resume +/** + * dpm_resume - Resume every device. + * + * Resume the devices that have either not gone through + * the late suspend, or that did go through it but also + * went through the early resume. + * + * Take devices from the dpm_off_list, resume them, + * and put them on the dpm_locked list. */ static void dpm_resume(void) { mutex_lock(&dpm_list_mtx); while(!list_empty(&dpm_off)) { - struct list_head * entry = dpm_off.next; - struct device * dev = to_device(entry); - - get_device(dev); - list_move_tail(entry, &dpm_active); + struct list_head *entry = dpm_off.next; + struct device *dev = to_device(entry); + list_move_tail(entry, &dpm_locked); mutex_unlock(&dpm_list_mtx); resume_device(dev); mutex_lock(&dpm_list_mtx); - put_device(dev); } mutex_unlock(&dpm_list_mtx); } - /** - * device_resume - Restore state of each device in system. + * unlock_all_devices - Release each device's semaphore * - * Walk the dpm_off list, remove each entry, resume the device, - * then add it to the dpm_active list. + * Go through the dpm_off list. Put each device on the dpm_active + * list and unlock it. */ - -void device_resume(void) +static void unlock_all_devices(void) { - might_sleep(); - mutex_lock(&dpm_mtx); - dpm_resume(); - mutex_unlock(&dpm_mtx); -} - -EXPORT_SYMBOL_GPL(device_resume); + mutex_lock(&dpm_list_mtx); + while (!list_empty(&dpm_locked)) { + struct list_head *entry = dpm_locked.prev; + struct device *dev = to_device(entry); + list_move(entry, &dpm_active); + up(&dev->sem); + } + mutex_unlock(&dpm_list_mtx); +} /** - * dpm_power_up - Power on some devices. - * - * Walk the dpm_off_irq list and power each device up. This - * is used for devices that required they be powered down with - * interrupts disabled. As devices are powered on, they are moved - * to the dpm_active list. + * unregister_dropped_devices - Unregister devices scheduled for removal * - * Interrupts must be disabled when calling this. + * Unregister all devices on the dpm_destroy list. */ - -static void dpm_power_up(void) +static void unregister_dropped_devices(void) { - while(!list_empty(&dpm_off_irq)) { - struct list_head * entry = dpm_off_irq.next; - struct device * dev = to_device(entry); + mutex_lock(&dpm_list_mtx); + while (!list_empty(&dpm_destroy)) { + struct list_head *entry = dpm_destroy.next; + struct device *dev = to_device(entry); - list_move_tail(entry, &dpm_off); - resume_device_early(dev); + up(&dev->sem); + mutex_unlock(&dpm_list_mtx); + /* This also removes the device from the list */ + device_unregister(dev); + mutex_lock(&dpm_list_mtx); } + mutex_unlock(&dpm_list_mtx); } - /** - * device_power_up - Turn on all devices that need special attention. + * device_resume - Restore state of each device in system. * - * Power on system devices then devices that required we shut them down - * with interrupts disabled. - * Called with interrupts disabled. + * Resume all the devices, unlock them all, and allow new + * devices to be registered once again. */ - -void device_power_up(void) +void device_resume(void) { - sysdev_resume(); - dpm_power_up(); + might_sleep(); + dpm_resume(); + unlock_all_devices(); + unregister_dropped_devices(); + up_write(&pm_sleep_rwsem); } - -EXPORT_SYMBOL_GPL(device_power_up); +EXPORT_SYMBOL_GPL(device_resume); /*------------------------- Suspend routines -------------------------*/ -/* - * The entries in the dpm_active list are in a depth first order, simply - * because children are guaranteed to be discovered after parents, and - * are inserted at the back of the list on discovery. - * - * All list on the suspend path are done in reverse order, so we operate - * on the leaves of the device tree (or forests, depending on how you want - * to look at it ;) first. As nodes are removed from the back of the list, - * they are inserted into the front of their destintation lists. - * - * Things are the reverse on the resume path - iterations are done in - * forward order, and nodes are inserted at the back of their destination - * lists. This way, the ancestors will be accessed before their descendents. - */ - static inline char *suspend_verb(u32 event) { switch (event) { @@ -222,7 +342,6 @@ static inline char *suspend_verb(u32 event) } } - static void suspend_device_dbg(struct device *dev, pm_message_t state, char *info) { @@ -232,16 +351,73 @@ suspend_device_dbg(struct device *dev, pm_message_t state, char *info) } /** - * suspend_device - Save state of one device. + * suspend_device_late - Shut down one device (late suspend). * @dev: Device. * @state: Power state device is entering. + * + * This is called with interrupts off and only a single CPU running. */ +static int suspend_device_late(struct device *dev, pm_message_t state) +{ + int error = 0; -static int suspend_device(struct device * dev, pm_message_t state) + if (dev->bus && dev->bus->suspend_late) { + suspend_device_dbg(dev, state, "LATE "); + error = dev->bus->suspend_late(dev, state); + suspend_report_result(dev->bus->suspend_late, error); + } + return error; +} + +/** + * device_power_down - Shut down special devices. + * @state: Power state to enter. + * + * Power down devices that require interrupts to be disabled + * and move them from the dpm_off list to the dpm_off_irq list. + * Then power down system devices. + * + * Must be called with interrupts disabled and only one CPU running. + */ +int device_power_down(pm_message_t state) +{ + int error = 0; + + while (!list_empty(&dpm_off)) { + struct list_head *entry = dpm_off.prev; + struct device *dev = to_device(entry); + + list_del_init(&dev->power.entry); + error = suspend_device_late(dev, state); + if (error) { + printk(KERN_ERR "Could not power down device %s: " + "error %d\n", + kobject_name(&dev->kobj), error); + if (list_empty(&dev->power.entry)) + list_add(&dev->power.entry, &dpm_off); + break; + } + if (list_empty(&dev->power.entry)) + list_add(&dev->power.entry, &dpm_off_irq); + } + + if (!error) + error = sysdev_suspend(state); + if (error) + dpm_power_up(); + return error; +} +EXPORT_SYMBOL_GPL(device_power_down); + +/** + * suspend_device - Save state of one device. + * @dev: Device. + * @state: Power state device is entering. + */ +int suspend_device(struct device *dev, pm_message_t state) { int error = 0; - down(&dev->sem); if (dev->power.power_state.event) { dev_dbg(dev, "PM: suspend %d-->%d\n", dev->power.power_state.event, state.event); @@ -264,123 +440,105 @@ static int suspend_device(struct device * dev, pm_message_t state) error = dev->bus->suspend(dev, state); suspend_report_result(dev->bus->suspend, error); } - up(&dev->sem); - return error; -} - - -/* - * This is called with interrupts off, only a single CPU - * running. We can't acquire a mutex or semaphore (and we don't - * need the protection) - */ -static int suspend_device_late(struct device *dev, pm_message_t state) -{ - int error = 0; - - if (dev->bus && dev->bus->suspend_late) { - suspend_device_dbg(dev, state, "LATE "); - error = dev->bus->suspend_late(dev, state); - suspend_report_result(dev->bus->suspend_late, error); - } return error; } /** - * device_suspend - Save state and stop all devices in system. - * @state: Power state to put each device in. + * dpm_suspend - Suspend every device. + * @state: Power state to put each device in. * - * Walk the dpm_active list, call ->suspend() for each device, and move - * it to the dpm_off list. + * Walk the dpm_locked list. Suspend each device and move it + * to the dpm_off list. * * (For historical reasons, if it returns -EAGAIN, that used to mean * that the device would be called again with interrupts disabled. * These days, we use the "suspend_late()" callback for that, so we * print a warning and consider it an error). - * - * If we get a different error, try and back out. - * - * If we hit a failure with any of the devices, call device_resume() - * above to bring the suspended devices back to life. - * */ - -int device_suspend(pm_message_t state) +static int dpm_suspend(pm_message_t state) { int error = 0; - might_sleep(); - mutex_lock(&dpm_mtx); mutex_lock(&dpm_list_mtx); - while (!list_empty(&dpm_active) && error == 0) { - struct list_head * entry = dpm_active.prev; - struct device * dev = to_device(entry); + while (!list_empty(&dpm_locked)) { + struct list_head *entry = dpm_locked.prev; + struct device *dev = to_device(entry); - get_device(dev); + list_del_init(&dev->power.entry); mutex_unlock(&dpm_list_mtx); - error = suspend_device(dev, state); - - mutex_lock(&dpm_list_mtx); - - /* Check if the device got removed */ - if (!list_empty(&dev->power.entry)) { - /* Move it to the dpm_off list */ - if (!error) - list_move(&dev->power.entry, &dpm_off); - } - if (error) + if (error) { printk(KERN_ERR "Could not suspend device %s: " - "error %d%s\n", - kobject_name(&dev->kobj), error, - error == -EAGAIN ? " (please convert to suspend_late)" : ""); - put_device(dev); + "error %d%s\n", + kobject_name(&dev->kobj), + error, + (error == -EAGAIN ? + " (please convert to suspend_late)" : + "")); + mutex_lock(&dpm_list_mtx); + if (list_empty(&dev->power.entry)) + list_add(&dev->power.entry, &dpm_locked); + mutex_unlock(&dpm_list_mtx); + break; + } + mutex_lock(&dpm_list_mtx); + if (list_empty(&dev->power.entry)) + list_add(&dev->power.entry, &dpm_off); } mutex_unlock(&dpm_list_mtx); - if (error) - dpm_resume(); - mutex_unlock(&dpm_mtx); return error; } -EXPORT_SYMBOL_GPL(device_suspend); - /** - * device_power_down - Shut down special devices. - * @state: Power state to enter. + * lock_all_devices - Acquire every device's semaphore * - * Walk the dpm_off_irq list, calling ->power_down() for each device that - * couldn't power down the device with interrupts enabled. When we're - * done, power down system devices. + * Go through the dpm_active list. Carefully lock each device's + * semaphore and put it in on the dpm_locked list. */ - -int device_power_down(pm_message_t state) +static void lock_all_devices(void) { - int error = 0; - struct device * dev; + mutex_lock(&dpm_list_mtx); + while (!list_empty(&dpm_active)) { + struct list_head *entry = dpm_active.next; + struct device *dev = to_device(entry); - while (!list_empty(&dpm_off)) { - struct list_head * entry = dpm_off.prev; + /* Required locking order is dev->sem first, + * then dpm_list_mutex. Hence this awkward code. + */ + get_device(dev); + mutex_unlock(&dpm_list_mtx); + down(&dev->sem); + mutex_lock(&dpm_list_mtx); - dev = to_device(entry); - error = suspend_device_late(dev, state); - if (error) - goto Error; - list_move(&dev->power.entry, &dpm_off_irq); + if (list_empty(entry)) + up(&dev->sem); /* Device was removed */ + else + list_move_tail(entry, &dpm_locked); + put_device(dev); } + mutex_unlock(&dpm_list_mtx); +} + +/** + * device_suspend - Save state and stop all devices in system. + * + * Prevent new devices from being registered, then lock all devices + * and suspend them. + */ +int device_suspend(pm_message_t state) +{ + int error; - error = sysdev_suspend(state); - Done: + might_sleep(); + down_write(&pm_sleep_rwsem); + lock_all_devices(); + error = dpm_suspend(state); + if (error) + device_resume(); return error; - Error: - printk(KERN_ERR "Could not power down device %s: " - "error %d\n", kobject_name(&dev->kobj), error); - dpm_power_up(); - goto Done; } - -EXPORT_SYMBOL_GPL(device_power_down); +EXPORT_SYMBOL_GPL(device_suspend); void __suspend_report_result(const char *function, void *fn, int ret) { diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 379da4e958e0d00fc637b00cac5215f41fb6cd45..6f0dfca8ebdd2437da619ab7a0c89abd7a60dcca 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -1,10 +1,3 @@ -/* - * shutdown.c - */ - -extern void device_shutdown(void); - - #ifdef CONFIG_PM_SLEEP /* @@ -20,6 +13,9 @@ static inline struct device *to_device(struct list_head *entry) extern void device_pm_add(struct device *); extern void device_pm_remove(struct device *); +extern void device_pm_schedule_removal(struct device *); +extern int pm_sleep_lock(void); +extern void pm_sleep_unlock(void); #else /* CONFIG_PM_SLEEP */ @@ -32,6 +28,15 @@ static inline void device_pm_remove(struct device *dev) { } +static inline int pm_sleep_lock(void) +{ + return 0; +} + +static inline void pm_sleep_unlock(void) +{ +} + #endif #ifdef CONFIG_PM diff --git a/drivers/base/power/shutdown.c b/drivers/base/power/shutdown.c deleted file mode 100644 index 56e8eaaac012cd544f69df0823aef84b023cfaaf..0000000000000000000000000000000000000000 --- a/drivers/base/power/shutdown.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * shutdown.c - power management functions for the device tree. - * - * Copyright (c) 2002-3 Patrick Mochel - * 2002-3 Open Source Development Lab - * - * This file is released under the GPLv2 - * - */ - -#include <linux/device.h> -#include <asm/semaphore.h> - -#include "../base.h" -#include "power.h" - -#define to_dev(node) container_of(node, struct device, kobj.entry) - - -/** - * We handle system devices differently - we suspend and shut them - * down last and resume them first. That way, we don't do anything stupid like - * shutting down the interrupt controller before any devices.. - * - * Note that there are not different stages for power management calls - - * they only get one called once when interrupts are disabled. - */ - - -/** - * device_shutdown - call ->shutdown() on each device to shutdown. - */ -void device_shutdown(void) -{ - struct device * dev, *devn; - - list_for_each_entry_safe_reverse(dev, devn, &devices_subsys.list, - kobj.entry) { - if (dev->bus && dev->bus->shutdown) { - dev_dbg(dev, "shutdown\n"); - dev->bus->shutdown(dev); - } else if (dev->driver && dev->driver->shutdown) { - dev_dbg(dev, "shutdown\n"); - dev->driver->shutdown(dev); - } - } -} - diff --git a/drivers/base/sys.c b/drivers/base/sys.c index ac7ff6d0c6e5c34460cfd1fcf4d76678b3e0533f..2f79c55acdcc6af406a9e03b469a4853eefee808 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -25,8 +25,6 @@ #include "base.h" -extern struct kset devices_subsys; - #define to_sysdev(k) container_of(k, struct sys_device, kobj) #define to_sysdev_attr(a) container_of(a, struct sysdev_attribute, attr) @@ -128,18 +126,17 @@ void sysdev_class_remove_file(struct sysdev_class *c, } EXPORT_SYMBOL_GPL(sysdev_class_remove_file); -/* - * declare system_subsys - */ -static decl_subsys(system, &ktype_sysdev_class, NULL); +static struct kset *system_kset; int sysdev_class_register(struct sysdev_class * cls) { pr_debug("Registering sysdev class '%s'\n", kobject_name(&cls->kset.kobj)); INIT_LIST_HEAD(&cls->drivers); - cls->kset.kobj.parent = &system_subsys.kobj; - cls->kset.kobj.kset = &system_subsys; + cls->kset.kobj.parent = &system_kset->kobj; + cls->kset.kobj.ktype = &ktype_sysdev_class; + cls->kset.kobj.kset = system_kset; + kobject_set_name(&cls->kset.kobj, cls->name); return kset_register(&cls->kset); } @@ -228,20 +225,15 @@ int sysdev_register(struct sys_device * sysdev) if (!cls) return -EINVAL; + pr_debug("Registering sys device '%s'\n", kobject_name(&sysdev->kobj)); + /* Make sure the kset is set */ sysdev->kobj.kset = &cls->kset; - /* But make sure we point to the right type for sysfs translation */ - sysdev->kobj.ktype = &ktype_sysdev; - error = kobject_set_name(&sysdev->kobj, "%s%d", - kobject_name(&cls->kset.kobj), sysdev->id); - if (error) - return error; - - pr_debug("Registering sys device '%s'\n", kobject_name(&sysdev->kobj)); - /* Register the object */ - error = kobject_register(&sysdev->kobj); + error = kobject_init_and_add(&sysdev->kobj, &ktype_sysdev, NULL, + "%s%d", kobject_name(&cls->kset.kobj), + sysdev->id); if (!error) { struct sysdev_driver * drv; @@ -258,6 +250,7 @@ int sysdev_register(struct sys_device * sysdev) } mutex_unlock(&sysdev_drivers_lock); } + kobject_uevent(&sysdev->kobj, KOBJ_ADD); return error; } @@ -272,7 +265,7 @@ void sysdev_unregister(struct sys_device * sysdev) } mutex_unlock(&sysdev_drivers_lock); - kobject_unregister(&sysdev->kobj); + kobject_put(&sysdev->kobj); } @@ -298,8 +291,7 @@ void sysdev_shutdown(void) pr_debug("Shutting Down System Devices\n"); mutex_lock(&sysdev_drivers_lock); - list_for_each_entry_reverse(cls, &system_subsys.list, - kset.kobj.entry) { + list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) { struct sys_device * sysdev; pr_debug("Shutting down type '%s':\n", @@ -361,9 +353,7 @@ int sysdev_suspend(pm_message_t state) pr_debug("Suspending System Devices\n"); - list_for_each_entry_reverse(cls, &system_subsys.list, - kset.kobj.entry) { - + list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) { pr_debug("Suspending type '%s':\n", kobject_name(&cls->kset.kobj)); @@ -414,8 +404,7 @@ int sysdev_suspend(pm_message_t state) } /* resume other classes */ - list_for_each_entry_continue(cls, &system_subsys.list, - kset.kobj.entry) { + list_for_each_entry_continue(cls, &system_kset->list, kset.kobj.entry) { list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) { pr_debug(" %s\n", kobject_name(&err_dev->kobj)); __sysdev_resume(err_dev); @@ -440,7 +429,7 @@ int sysdev_resume(void) pr_debug("Resuming System Devices\n"); - list_for_each_entry(cls, &system_subsys.list, kset.kobj.entry) { + list_for_each_entry(cls, &system_kset->list, kset.kobj.entry) { struct sys_device * sysdev; pr_debug("Resuming type '%s':\n", @@ -458,8 +447,10 @@ int sysdev_resume(void) int __init system_bus_init(void) { - system_subsys.kobj.parent = &devices_subsys.kobj; - return subsystem_register(&system_subsys); + system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj); + if (!system_kset) + return -ENOMEM; + return 0; } EXPORT_SYMBOL_GPL(sysdev_register); diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index ad00b3d94711d09b6344ea36cd73ce21418932a1..826d12381e21f546c099be3079604ca5412868f0 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -15,8 +15,10 @@ static struct kmem_cache *buf_pool_cache; -static ssize_t aoedisk_show_state(struct gendisk * disk, char *page) +static ssize_t aoedisk_show_state(struct device *dev, + struct device_attribute *attr, char *page) { + struct gendisk *disk = dev_to_disk(dev); struct aoedev *d = disk->private_data; return snprintf(page, PAGE_SIZE, @@ -26,50 +28,47 @@ static ssize_t aoedisk_show_state(struct gendisk * disk, char *page) (d->nopen && !(d->flags & DEVFL_UP)) ? ",closewait" : ""); /* I'd rather see nopen exported so we can ditch closewait */ } -static ssize_t aoedisk_show_mac(struct gendisk * disk, char *page) +static ssize_t aoedisk_show_mac(struct device *dev, + struct device_attribute *attr, char *page) { + struct gendisk *disk = dev_to_disk(dev); struct aoedev *d = disk->private_data; return snprintf(page, PAGE_SIZE, "%012llx\n", (unsigned long long)mac_addr(d->addr)); } -static ssize_t aoedisk_show_netif(struct gendisk * disk, char *page) +static ssize_t aoedisk_show_netif(struct device *dev, + struct device_attribute *attr, char *page) { + struct gendisk *disk = dev_to_disk(dev); struct aoedev *d = disk->private_data; return snprintf(page, PAGE_SIZE, "%s\n", d->ifp->name); } /* firmware version */ -static ssize_t aoedisk_show_fwver(struct gendisk * disk, char *page) +static ssize_t aoedisk_show_fwver(struct device *dev, + struct device_attribute *attr, char *page) { + struct gendisk *disk = dev_to_disk(dev); struct aoedev *d = disk->private_data; return snprintf(page, PAGE_SIZE, "0x%04x\n", (unsigned int) d->fw_ver); } -static struct disk_attribute disk_attr_state = { - .attr = {.name = "state", .mode = S_IRUGO }, - .show = aoedisk_show_state -}; -static struct disk_attribute disk_attr_mac = { - .attr = {.name = "mac", .mode = S_IRUGO }, - .show = aoedisk_show_mac -}; -static struct disk_attribute disk_attr_netif = { - .attr = {.name = "netif", .mode = S_IRUGO }, - .show = aoedisk_show_netif -}; -static struct disk_attribute disk_attr_fwver = { - .attr = {.name = "firmware-version", .mode = S_IRUGO }, - .show = aoedisk_show_fwver +static DEVICE_ATTR(state, S_IRUGO, aoedisk_show_state, NULL); +static DEVICE_ATTR(mac, S_IRUGO, aoedisk_show_mac, NULL); +static DEVICE_ATTR(netif, S_IRUGO, aoedisk_show_netif, NULL); +static struct device_attribute dev_attr_firmware_version = { + .attr = { .name = "firmware-version", .mode = S_IRUGO, .owner = THIS_MODULE }, + .show = aoedisk_show_fwver, }; static struct attribute *aoe_attrs[] = { - &disk_attr_state.attr, - &disk_attr_mac.attr, - &disk_attr_netif.attr, - &disk_attr_fwver.attr, - NULL + &dev_attr_state.attr, + &dev_attr_mac.attr, + &dev_attr_netif.attr, + &dev_attr_firmware_version.attr, + NULL, }; static const struct attribute_group attr_group = { @@ -79,12 +78,12 @@ static const struct attribute_group attr_group = { static int aoedisk_add_sysfs(struct aoedev *d) { - return sysfs_create_group(&d->gd->kobj, &attr_group); + return sysfs_create_group(&d->gd->dev.kobj, &attr_group); } void aoedisk_rm_sysfs(struct aoedev *d) { - sysfs_remove_group(&d->gd->kobj, &attr_group); + sysfs_remove_group(&d->gd->dev.kobj, &attr_group); } static int diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c index 39e563ea08782cf242972b42d3b8c4795e5a83a4..d5480e34cb22fbc27b88275a3cfec71ca3714484 100644 --- a/drivers/block/aoe/aoechr.c +++ b/drivers/block/aoe/aoechr.c @@ -259,9 +259,8 @@ aoechr_init(void) return PTR_ERR(aoe_class); } for (i = 0; i < ARRAY_SIZE(chardevs); ++i) - class_device_create(aoe_class, NULL, - MKDEV(AOE_MAJOR, chardevs[i].minor), - NULL, chardevs[i].name); + device_create(aoe_class, NULL, + MKDEV(AOE_MAJOR, chardevs[i].minor), chardevs[i].name); return 0; } @@ -272,7 +271,7 @@ aoechr_exit(void) int i; for (i = 0; i < ARRAY_SIZE(chardevs); ++i) - class_device_destroy(aoe_class, MKDEV(AOE_MAJOR, chardevs[i].minor)); + device_destroy(aoe_class, MKDEV(AOE_MAJOR, chardevs[i].minor)); class_destroy(aoe_class); unregister_chrdev(AOE_MAJOR, "aoechr"); } diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index b4c0888aedc3113c8eb442726a4237c9f7d9dd92..ba9b17e507e000efb3f37c644373f43812eabd2e 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -375,14 +375,17 @@ static struct request *nbd_read_stat(struct nbd_device *lo) return NULL; } -static ssize_t pid_show(struct gendisk *disk, char *page) +static ssize_t pid_show(struct device *dev, + struct device_attribute *attr, char *buf) { - return sprintf(page, "%ld\n", + struct gendisk *disk = dev_to_disk(dev); + + return sprintf(buf, "%ld\n", (long) ((struct nbd_device *)disk->private_data)->pid); } -static struct disk_attribute pid_attr = { - .attr = { .name = "pid", .mode = S_IRUGO }, +static struct device_attribute pid_attr = { + .attr = { .name = "pid", .mode = S_IRUGO, .owner = THIS_MODULE }, .show = pid_show, }; @@ -394,7 +397,7 @@ static int nbd_do_it(struct nbd_device *lo) BUG_ON(lo->magic != LO_MAGIC); lo->pid = current->pid; - ret = sysfs_create_file(&lo->disk->kobj, &pid_attr.attr); + ret = sysfs_create_file(&lo->disk->dev.kobj, &pid_attr.attr); if (ret) { printk(KERN_ERR "nbd: sysfs_create_file failed!"); return ret; @@ -403,7 +406,7 @@ static int nbd_do_it(struct nbd_device *lo) while ((req = nbd_read_stat(lo)) != NULL) nbd_end_request(req); - sysfs_remove_file(&lo->disk->kobj, &pid_attr.attr); + sysfs_remove_file(&lo->disk->dev.kobj, &pid_attr.attr); return 0; } diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c index d89e7d32a3b604716a63a03edf7ad0fd3492f6a5..ab86e23ddc69dc36272c6bf60ebe915168177b58 100644 --- a/drivers/block/paride/pg.c +++ b/drivers/block/paride/pg.c @@ -676,8 +676,8 @@ static int __init pg_init(void) for (unit = 0; unit < PG_UNITS; unit++) { struct pg *dev = &devices[unit]; if (dev->present) - class_device_create(pg_class, NULL, MKDEV(major, unit), - NULL, "pg%u", unit); + device_create(pg_class, NULL, MKDEV(major, unit), + "pg%u", unit); } err = 0; goto out; @@ -695,7 +695,7 @@ static void __exit pg_exit(void) for (unit = 0; unit < PG_UNITS; unit++) { struct pg *dev = &devices[unit]; if (dev->present) - class_device_destroy(pg_class, MKDEV(major, unit)); + device_destroy(pg_class, MKDEV(major, unit)); } class_destroy(pg_class); unregister_chrdev(major, name); diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c index b91accf12656581066811fa68c18e78cfb655018..76096cad798f1c54708a498a90d5eb85eb105f83 100644 --- a/drivers/block/paride/pt.c +++ b/drivers/block/paride/pt.c @@ -972,10 +972,10 @@ static int __init pt_init(void) for (unit = 0; unit < PT_UNITS; unit++) if (pt[unit].present) { - class_device_create(pt_class, NULL, MKDEV(major, unit), - NULL, "pt%d", unit); - class_device_create(pt_class, NULL, MKDEV(major, unit + 128), - NULL, "pt%dn", unit); + device_create(pt_class, NULL, MKDEV(major, unit), + "pt%d", unit); + device_create(pt_class, NULL, MKDEV(major, unit + 128), + "pt%dn", unit); } goto out; @@ -990,8 +990,8 @@ static void __exit pt_exit(void) int unit; for (unit = 0; unit < PT_UNITS; unit++) if (pt[unit].present) { - class_device_destroy(pt_class, MKDEV(major, unit)); - class_device_destroy(pt_class, MKDEV(major, unit + 128)); + device_destroy(pt_class, MKDEV(major, unit)); + device_destroy(pt_class, MKDEV(major, unit + 128)); } class_destroy(pt_class); unregister_chrdev(major, name); diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 3535ef896677a28dcc352654c880587e9bc463c2..e9de1712e5a0b1b98b8cc1ce95d59d8daf0b615e 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -110,17 +110,18 @@ static struct pktcdvd_kobj* pkt_kobj_create(struct pktcdvd_device *pd, struct kobj_type* ktype) { struct pktcdvd_kobj *p; + int error; + p = kzalloc(sizeof(*p), GFP_KERNEL); if (!p) return NULL; - kobject_set_name(&p->kobj, "%s", name); - p->kobj.parent = parent; - p->kobj.ktype = ktype; p->pd = pd; - if (kobject_register(&p->kobj) != 0) { + error = kobject_init_and_add(&p->kobj, ktype, parent, "%s", name); + if (error) { kobject_put(&p->kobj); return NULL; } + kobject_uevent(&p->kobj, KOBJ_ADD); return p; } /* @@ -129,7 +130,7 @@ static struct pktcdvd_kobj* pkt_kobj_create(struct pktcdvd_device *pd, static void pkt_kobj_remove(struct pktcdvd_kobj *p) { if (p) - kobject_unregister(&p->kobj); + kobject_put(&p->kobj); } /* * default release function for pktcdvd kernel objects. @@ -301,18 +302,16 @@ static struct kobj_type kobj_pkt_type_wqueue = { static void pkt_sysfs_dev_new(struct pktcdvd_device *pd) { if (class_pktcdvd) { - pd->clsdev = class_device_create(class_pktcdvd, - NULL, pd->pkt_dev, - NULL, "%s", pd->name); - if (IS_ERR(pd->clsdev)) - pd->clsdev = NULL; + pd->dev = device_create(class_pktcdvd, NULL, pd->pkt_dev, "%s", pd->name); + if (IS_ERR(pd->dev)) + pd->dev = NULL; } - if (pd->clsdev) { + if (pd->dev) { pd->kobj_stat = pkt_kobj_create(pd, "stat", - &pd->clsdev->kobj, + &pd->dev->kobj, &kobj_pkt_type_stat); pd->kobj_wqueue = pkt_kobj_create(pd, "write_queue", - &pd->clsdev->kobj, + &pd->dev->kobj, &kobj_pkt_type_wqueue); } } @@ -322,7 +321,7 @@ static void pkt_sysfs_dev_remove(struct pktcdvd_device *pd) pkt_kobj_remove(pd->kobj_stat); pkt_kobj_remove(pd->kobj_wqueue); if (class_pktcdvd) - class_device_destroy(class_pktcdvd, pd->pkt_dev); + device_destroy(class_pktcdvd, pd->pkt_dev); } diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 2e3a0d4bc4c299a213362311355ebe8303ca3d07..466629594776fc4af443dec3ca4dc0fa767d0c4e 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -373,6 +373,16 @@ config ISTALLION To compile this driver as a module, choose M here: the module will be called istallion. +config NOZOMI + tristate "HSDPA Broadband Wireless Data Card - Globe Trotter" + depends on PCI && EXPERIMENTAL + help + If you have a HSDPA driver Broadband Wireless Data Card - + Globe Trotter PCMCIA card, say Y here. + + To compile this driver as a module, choose M here, the module + will be called nozomi. + config A2232 tristate "Commodore A2232 serial support (EXPERIMENTAL)" depends on EXPERIMENTAL && ZORRO && BROKEN_ON_SMP diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 07304d50e0cbcbde89e5cb26273bfbad73fdc3fc..96fc01eddefe805553ea1a834ba2f06a7f25c3b0 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_SERIAL167) += serial167.o obj-$(CONFIG_CYCLADES) += cyclades.o obj-$(CONFIG_STALLION) += stallion.o obj-$(CONFIG_ISTALLION) += istallion.o +obj-$(CONFIG_NOZOMI) += nozomi.o obj-$(CONFIG_DIGIEPCA) += epca.o obj-$(CONFIG_SPECIALIX) += specialix.o obj-$(CONFIG_MOXA_INTELLIO) += moxa.o diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 8252f86685385f341aa6f34797d52581264ed543..480fae29c9b2a508305d67e870684136c8f7581e 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -27,7 +27,7 @@ #include <linux/init.h> #include <linux/kbd_kern.h> #include <linux/kernel.h> -#include <linux/kobject.h> +#include <linux/kref.h> #include <linux/kthread.h> #include <linux/list.h> #include <linux/module.h> @@ -89,7 +89,7 @@ struct hvc_struct { int irq_requested; int irq; struct list_head next; - struct kobject kobj; /* ref count & hvc_struct lifetime */ + struct kref kref; /* ref count & hvc_struct lifetime */ }; /* dynamic list of hvc_struct instances */ @@ -110,7 +110,7 @@ static int last_hvc = -1; /* * Do not call this function with either the hvc_structs_lock or the hvc_struct - * lock held. If successful, this function increments the kobject reference + * lock held. If successful, this function increments the kref reference * count against the target hvc_struct so it should be released when finished. */ static struct hvc_struct *hvc_get_by_index(int index) @@ -123,7 +123,7 @@ static struct hvc_struct *hvc_get_by_index(int index) list_for_each_entry(hp, &hvc_structs, next) { spin_lock_irqsave(&hp->lock, flags); if (hp->index == index) { - kobject_get(&hp->kobj); + kref_get(&hp->kref); spin_unlock_irqrestore(&hp->lock, flags); spin_unlock(&hvc_structs_lock); return hp; @@ -242,6 +242,23 @@ static int __init hvc_console_init(void) } console_initcall(hvc_console_init); +/* callback when the kboject ref count reaches zero. */ +static void destroy_hvc_struct(struct kref *kref) +{ + struct hvc_struct *hp = container_of(kref, struct hvc_struct, kref); + unsigned long flags; + + spin_lock(&hvc_structs_lock); + + spin_lock_irqsave(&hp->lock, flags); + list_del(&(hp->next)); + spin_unlock_irqrestore(&hp->lock, flags); + + spin_unlock(&hvc_structs_lock); + + kfree(hp); +} + /* * hvc_instantiate() is an early console discovery method which locates * consoles * prior to the vio subsystem discovering them. Hotplugged @@ -261,7 +278,7 @@ int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops) /* make sure no no tty has been registered in this index */ hp = hvc_get_by_index(index); if (hp) { - kobject_put(&hp->kobj); + kref_put(&hp->kref, destroy_hvc_struct); return -1; } @@ -318,9 +335,8 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) unsigned long flags; int irq = 0; int rc = 0; - struct kobject *kobjp; - /* Auto increments kobject reference if found. */ + /* Auto increments kref reference if found. */ if (!(hp = hvc_get_by_index(tty->index))) return -ENODEV; @@ -341,8 +357,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) if (irq) hp->irq_requested = 1; - kobjp = &hp->kobj; - spin_unlock_irqrestore(&hp->lock, flags); /* check error, fallback to non-irq */ if (irq) @@ -352,7 +366,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) * If the request_irq() fails and we return an error. The tty layer * will call hvc_close() after a failed open but we don't want to clean * up there so we'll clean up here and clear out the previously set - * tty fields and return the kobject reference. + * tty fields and return the kref reference. */ if (rc) { spin_lock_irqsave(&hp->lock, flags); @@ -360,7 +374,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) hp->irq_requested = 0; spin_unlock_irqrestore(&hp->lock, flags); tty->driver_data = NULL; - kobject_put(kobjp); + kref_put(&hp->kref, destroy_hvc_struct); printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc); } /* Force wakeup of the polling thread */ @@ -372,7 +386,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) static void hvc_close(struct tty_struct *tty, struct file * filp) { struct hvc_struct *hp; - struct kobject *kobjp; int irq = 0; unsigned long flags; @@ -382,7 +395,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) /* * No driver_data means that this close was issued after a failed * hvc_open by the tty layer's release_dev() function and we can just - * exit cleanly because the kobject reference wasn't made. + * exit cleanly because the kref reference wasn't made. */ if (!tty->driver_data) return; @@ -390,7 +403,6 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) hp = tty->driver_data; spin_lock_irqsave(&hp->lock, flags); - kobjp = &hp->kobj; if (--hp->count == 0) { if (hp->irq_requested) irq = hp->irq; @@ -417,7 +429,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) spin_unlock_irqrestore(&hp->lock, flags); } - kobject_put(kobjp); + kref_put(&hp->kref, destroy_hvc_struct); } static void hvc_hangup(struct tty_struct *tty) @@ -426,7 +438,6 @@ static void hvc_hangup(struct tty_struct *tty) unsigned long flags; int irq = 0; int temp_open_count; - struct kobject *kobjp; if (!hp) return; @@ -443,7 +454,6 @@ static void hvc_hangup(struct tty_struct *tty) return; } - kobjp = &hp->kobj; temp_open_count = hp->count; hp->count = 0; hp->n_outbuf = 0; @@ -457,7 +467,7 @@ static void hvc_hangup(struct tty_struct *tty) free_irq(irq, hp); while(temp_open_count) { --temp_open_count; - kobject_put(kobjp); + kref_put(&hp->kref, destroy_hvc_struct); } } @@ -729,27 +739,6 @@ static const struct tty_operations hvc_ops = { .chars_in_buffer = hvc_chars_in_buffer, }; -/* callback when the kboject ref count reaches zero. */ -static void destroy_hvc_struct(struct kobject *kobj) -{ - struct hvc_struct *hp = container_of(kobj, struct hvc_struct, kobj); - unsigned long flags; - - spin_lock(&hvc_structs_lock); - - spin_lock_irqsave(&hp->lock, flags); - list_del(&(hp->next)); - spin_unlock_irqrestore(&hp->lock, flags); - - spin_unlock(&hvc_structs_lock); - - kfree(hp); -} - -static struct kobj_type hvc_kobj_type = { - .release = destroy_hvc_struct, -}; - struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, struct hv_ops *ops, int outbuf_size) { @@ -776,8 +765,7 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, hp->outbuf_size = outbuf_size; hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))]; - kobject_init(&hp->kobj); - hp->kobj.ktype = &hvc_kobj_type; + kref_init(&hp->kref); spin_lock_init(&hp->lock); spin_lock(&hvc_structs_lock); @@ -806,12 +794,10 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, int __devexit hvc_remove(struct hvc_struct *hp) { unsigned long flags; - struct kobject *kobjp; struct tty_struct *tty; spin_lock_irqsave(&hp->lock, flags); tty = hp->tty; - kobjp = &hp->kobj; if (hp->index < MAX_NR_HVC_CONSOLES) vtermnos[hp->index] = -1; @@ -821,12 +807,12 @@ int __devexit hvc_remove(struct hvc_struct *hp) spin_unlock_irqrestore(&hp->lock, flags); /* - * We 'put' the instance that was grabbed when the kobject instance - * was initialized using kobject_init(). Let the last holder of this - * kobject cause it to be removed, which will probably be the tty_hangup + * We 'put' the instance that was grabbed when the kref instance + * was initialized using kref_init(). Let the last holder of this + * kref cause it to be removed, which will probably be the tty_hangup * below. */ - kobject_put(kobjp); + kref_put(&hp->kref, destroy_hvc_struct); /* * This function call will auto chain call hvc_hangup. The tty should diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index 69d8866de783f36a70ff38d63d4b47d9f0688385..fd7559084b8204479c76dc0cbd72da06fe431126 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c @@ -57,11 +57,7 @@ * rescanning partner information upon a user's request. * * Each vty-server, prior to being exposed to this driver is reference counted - * using the 2.6 Linux kernel kobject construct. This kobject is also used by - * the vio bus to provide a vio device sysfs entry that this driver attaches - * device specific attributes to, including partner information. The vio bus - * framework also provides a sysfs entry for each vio driver. The hvcs driver - * provides driver attributes in this entry. + * using the 2.6 Linux kernel kref construct. * * For direction on installation and usage of this driver please reference * Documentation/powerpc/hvcs.txt. @@ -71,7 +67,7 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/kernel.h> -#include <linux/kobject.h> +#include <linux/kref.h> #include <linux/kthread.h> #include <linux/list.h> #include <linux/major.h> @@ -293,12 +289,12 @@ struct hvcs_struct { int chars_in_buffer; /* - * Any variable below the kobject is valid before a tty is connected and + * Any variable below the kref is valid before a tty is connected and * stays valid after the tty is disconnected. These shouldn't be * whacked until the koject refcount reaches zero though some entries * may be changed via sysfs initiatives. */ - struct kobject kobj; /* ref count & hvcs_struct lifetime */ + struct kref kref; /* ref count & hvcs_struct lifetime */ int connected; /* is the vty-server currently connected to a vty? */ uint32_t p_unit_address; /* partner unit address */ uint32_t p_partition_ID; /* partner partition ID */ @@ -307,8 +303,8 @@ struct hvcs_struct { struct vio_dev *vdev; }; -/* Required to back map a kobject to its containing object */ -#define from_kobj(kobj) container_of(kobj, struct hvcs_struct, kobj) +/* Required to back map a kref to its containing object */ +#define from_kref(k) container_of(k, struct hvcs_struct, kref) static struct list_head hvcs_structs = LIST_HEAD_INIT(hvcs_structs); static DEFINE_SPINLOCK(hvcs_structs_lock); @@ -334,7 +330,6 @@ static void hvcs_partner_free(struct hvcs_struct *hvcsd); static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address, unsigned int irq, struct vio_dev *dev); -static void destroy_hvcs_struct(struct kobject *kobj); static int hvcs_open(struct tty_struct *tty, struct file *filp); static void hvcs_close(struct tty_struct *tty, struct file *filp); static void hvcs_hangup(struct tty_struct * tty); @@ -703,10 +698,10 @@ static void hvcs_return_index(int index) hvcs_index_list[index] = -1; } -/* callback when the kboject ref count reaches zero */ -static void destroy_hvcs_struct(struct kobject *kobj) +/* callback when the kref ref count reaches zero */ +static void destroy_hvcs_struct(struct kref *kref) { - struct hvcs_struct *hvcsd = from_kobj(kobj); + struct hvcs_struct *hvcsd = from_kref(kref); struct vio_dev *vdev; unsigned long flags; @@ -743,10 +738,6 @@ static void destroy_hvcs_struct(struct kobject *kobj) kfree(hvcsd); } -static struct kobj_type hvcs_kobj_type = { - .release = destroy_hvcs_struct, -}; - static int hvcs_get_index(void) { int i; @@ -791,9 +782,7 @@ static int __devinit hvcs_probe( spin_lock_init(&hvcsd->lock); /* Automatically incs the refcount the first time */ - kobject_init(&hvcsd->kobj); - /* Set up the callback for terminating the hvcs_struct's life */ - hvcsd->kobj.ktype = &hvcs_kobj_type; + kref_init(&hvcsd->kref); hvcsd->vdev = dev; dev->dev.driver_data = hvcsd; @@ -844,7 +833,6 @@ static int __devexit hvcs_remove(struct vio_dev *dev) { struct hvcs_struct *hvcsd = dev->dev.driver_data; unsigned long flags; - struct kobject *kobjp; struct tty_struct *tty; if (!hvcsd) @@ -856,15 +844,13 @@ static int __devexit hvcs_remove(struct vio_dev *dev) tty = hvcsd->tty; - kobjp = &hvcsd->kobj; - spin_unlock_irqrestore(&hvcsd->lock, flags); /* * Let the last holder of this object cause it to be removed, which * would probably be tty_hangup below. */ - kobject_put (kobjp); + kref_put(&hvcsd->kref, destroy_hvcs_struct); /* * The hangup is a scheduled function which will auto chain call @@ -1086,7 +1072,7 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address, } /* - * This always increments the kobject ref count if the call is successful. + * This always increments the kref ref count if the call is successful. * Please remember to dec when you are done with the instance. * * NOTICE: Do NOT hold either the hvcs_struct.lock or hvcs_structs_lock when @@ -1103,7 +1089,7 @@ static struct hvcs_struct *hvcs_get_by_index(int index) list_for_each_entry(hvcsd, &hvcs_structs, next) { spin_lock_irqsave(&hvcsd->lock, flags); if (hvcsd->index == index) { - kobject_get(&hvcsd->kobj); + kref_get(&hvcsd->kref); spin_unlock_irqrestore(&hvcsd->lock, flags); spin_unlock(&hvcs_structs_lock); return hvcsd; @@ -1129,14 +1115,13 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) unsigned int irq; struct vio_dev *vdev; unsigned long unit_address; - struct kobject *kobjp; if (tty->driver_data) goto fast_open; /* * Is there a vty-server that shares the same index? - * This function increments the kobject index. + * This function increments the kref index. */ if (!(hvcsd = hvcs_get_by_index(tty->index))) { printk(KERN_WARNING "HVCS: open failed, no device associated" @@ -1181,7 +1166,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) * and will grab the spinlock and free the connection if it fails. */ if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) { - kobject_put(&hvcsd->kobj); + kref_put(&hvcsd->kref, destroy_hvcs_struct); printk(KERN_WARNING "HVCS: enable device failed.\n"); return rc; } @@ -1192,17 +1177,11 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) hvcsd = tty->driver_data; spin_lock_irqsave(&hvcsd->lock, flags); - if (!kobject_get(&hvcsd->kobj)) { - spin_unlock_irqrestore(&hvcsd->lock, flags); - printk(KERN_ERR "HVCS: Kobject of open" - " hvcs doesn't exist.\n"); - return -EFAULT; /* Is this the right return value? */ - } - + kref_get(&hvcsd->kref); hvcsd->open_count++; - hvcsd->todo_mask |= HVCS_SCHED_READ; spin_unlock_irqrestore(&hvcsd->lock, flags); + open_success: hvcs_kick(); @@ -1212,9 +1191,8 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) return 0; error_release: - kobjp = &hvcsd->kobj; spin_unlock_irqrestore(&hvcsd->lock, flags); - kobject_put(&hvcsd->kobj); + kref_put(&hvcsd->kref, destroy_hvcs_struct); printk(KERN_WARNING "HVCS: partner connect failed.\n"); return retval; @@ -1224,7 +1202,6 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) { struct hvcs_struct *hvcsd; unsigned long flags; - struct kobject *kobjp; int irq = NO_IRQ; /* @@ -1245,7 +1222,6 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) hvcsd = tty->driver_data; spin_lock_irqsave(&hvcsd->lock, flags); - kobjp = &hvcsd->kobj; if (--hvcsd->open_count == 0) { vio_disable_interrupts(hvcsd->vdev); @@ -1270,7 +1246,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) tty->driver_data = NULL; free_irq(irq, hvcsd); - kobject_put(kobjp); + kref_put(&hvcsd->kref, destroy_hvcs_struct); return; } else if (hvcsd->open_count < 0) { printk(KERN_ERR "HVCS: vty-server@%X open_count: %d" @@ -1279,7 +1255,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) } spin_unlock_irqrestore(&hvcsd->lock, flags); - kobject_put(kobjp); + kref_put(&hvcsd->kref, destroy_hvcs_struct); } static void hvcs_hangup(struct tty_struct * tty) @@ -1287,21 +1263,17 @@ static void hvcs_hangup(struct tty_struct * tty) struct hvcs_struct *hvcsd = tty->driver_data; unsigned long flags; int temp_open_count; - struct kobject *kobjp; int irq = NO_IRQ; spin_lock_irqsave(&hvcsd->lock, flags); - /* Preserve this so that we know how many kobject refs to put */ + /* Preserve this so that we know how many kref refs to put */ temp_open_count = hvcsd->open_count; /* - * Don't kobject put inside the spinlock because the destruction + * Don't kref put inside the spinlock because the destruction * callback may use the spinlock and it may get called before the - * spinlock has been released. Get a pointer to the kobject and - * kobject_put on that after releasing the spinlock. + * spinlock has been released. */ - kobjp = &hvcsd->kobj; - vio_disable_interrupts(hvcsd->vdev); hvcsd->todo_mask = 0; @@ -1324,7 +1296,7 @@ static void hvcs_hangup(struct tty_struct * tty) free_irq(irq, hvcsd); /* - * We need to kobject_put() for every open_count we have since the + * We need to kref_put() for every open_count we have since the * tty_hangup() function doesn't invoke a close per open connection on a * non-console device. */ @@ -1335,7 +1307,7 @@ static void hvcs_hangup(struct tty_struct * tty) * NOTE: If this hangup was signaled from user space then the * final put will never happen. */ - kobject_put(kobjp); + kref_put(&hvcsd->kref, destroy_hvcs_struct); } } diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c new file mode 100644 index 0000000000000000000000000000000000000000..6076e662886a43fc3b863ab3bd6022e0e8041f0e --- /dev/null +++ b/drivers/char/nozomi.c @@ -0,0 +1,1993 @@ +/* + * nozomi.c -- HSDPA driver Broadband Wireless Data Card - Globe Trotter + * + * Written by: Ulf Jakobsson, + * Jan �erfeldt, + * Stefan Thomasson, + * + * Maintained by: Paul Hardwick (p.hardwick@option.com) + * + * Patches: + * Locking code changes for Vodafone by Sphere Systems Ltd, + * Andrew Bird (ajb@spheresystems.co.uk ) + * & Phil Sanderson + * + * Source has been ported from an implementation made by Filip Aben @ Option + * + * -------------------------------------------------------------------------- + * + * Copyright (c) 2005,2006 Option Wireless Sweden AB + * Copyright (c) 2006 Sphere Systems Ltd + * Copyright (c) 2006 Option Wireless n/v + * All rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * -------------------------------------------------------------------------- + */ + +/* + * CHANGELOG + * Version 2.1d + * 11-November-2007 Jiri Slaby, Frank Seidel + * - Big rework of multicard support by Jiri + * - Major cleanups (semaphore to mutex, endianess, no major reservation) + * - Optimizations + * + * Version 2.1c + * 30-October-2007 Frank Seidel + * - Completed multicard support + * - Minor cleanups + * + * Version 2.1b + * 07-August-2007 Frank Seidel + * - Minor cleanups + * - theoretical multicard support + * + * Version 2.1 + * 03-July-2006 Paul Hardwick + * + * - Stability Improvements. Incorporated spinlock wraps patch. + * - Updated for newer 2.6.14+ kernels (tty_buffer_request_room) + * - using __devexit macro for tty + * + * + * Version 2.0 + * 08-feb-2006 15:34:10:Ulf + * + * -Fixed issue when not waking up line disipine layer, could probably result + * in better uplink performance for 2.4. + * + * -Fixed issue with big endian during initalization, now proper toggle flags + * are handled between preloader and maincode. + * + * -Fixed flow control issue. + * + * -Added support for setting DTR. + * + * -For 2.4 kernels, removing temporary buffer that's not needed. + * + * -Reading CTS only for modem port (only port that supports it). + * + * -Return 0 in write_room instead of netative value, it's not handled in + * upper layer. + * + * -------------------------------------------------------------------------- + * Version 1.0 + * + * First version of driver, only tested with card of type F32_2. + * Works fine with 2.4 and 2.6 kernels. + * Driver also support big endian architecture. + */ + +/* Enable this to have a lot of debug printouts */ +#define DEBUG + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/ioport.h> +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> +#include <linux/serial.h> +#include <linux/interrupt.h> +#include <linux/kmod.h> +#include <linux/init.h> +#include <linux/kfifo.h> +#include <linux/uaccess.h> +#include <asm/byteorder.h> + +#include <linux/delay.h> + + +#define VERSION_STRING DRIVER_DESC " 2.1d (build date: " \ + __DATE__ " " __TIME__ ")" + +/* Macros definitions */ + +/* Default debug printout level */ +#define NOZOMI_DEBUG_LEVEL 0x00 + +#define P_BUF_SIZE 128 +#define NFO(_err_flag_, args...) \ +do { \ + char tmp[P_BUF_SIZE]; \ + snprintf(tmp, sizeof(tmp), ##args); \ + printk(_err_flag_ "[%d] %s(): %s\n", __LINE__, \ + __FUNCTION__, tmp); \ +} while (0) + +#define DBG1(args...) D_(0x01, ##args) +#define DBG2(args...) D_(0x02, ##args) +#define DBG3(args...) D_(0x04, ##args) +#define DBG4(args...) D_(0x08, ##args) +#define DBG5(args...) D_(0x10, ##args) +#define DBG6(args...) D_(0x20, ##args) +#define DBG7(args...) D_(0x40, ##args) +#define DBG8(args...) D_(0x80, ##args) + +#ifdef DEBUG +/* Do we need this settable at runtime? */ +static int debug = NOZOMI_DEBUG_LEVEL; + +#define D(lvl, args...) do {if (lvl & debug) NFO(KERN_DEBUG, ##args); } \ + while (0) +#define D_(lvl, args...) D(lvl, ##args) + +/* These printouts are always printed */ + +#else +static int debug; +#define D_(lvl, args...) +#endif + +/* TODO: rewrite to optimize macros... */ + +#define TMP_BUF_MAX 256 + +#define DUMP(buf__,len__) \ + do { \ + char tbuf[TMP_BUF_MAX] = {0};\ + if (len__ > 1) {\ + snprintf(tbuf, len__ > TMP_BUF_MAX ? TMP_BUF_MAX : len__, "%s", buf__);\ + if (tbuf[len__-2] == '\r') {\ + tbuf[len__-2] = 'r';\ + } \ + DBG1("SENDING: '%s' (%d+n)", tbuf, len__);\ + } else {\ + DBG1("SENDING: '%s' (%d)", tbuf, len__);\ + } \ +} while (0) + +/* Defines */ +#define NOZOMI_NAME "nozomi" +#define NOZOMI_NAME_TTY "nozomi_tty" +#define DRIVER_DESC "Nozomi driver" + +#define NTTY_TTY_MAXMINORS 256 +#define NTTY_FIFO_BUFFER_SIZE 8192 + +/* Must be power of 2 */ +#define FIFO_BUFFER_SIZE_UL 8192 + +/* Size of tmp send buffer to card */ +#define SEND_BUF_MAX 1024 +#define RECEIVE_BUF_MAX 4 + + +/* Define all types of vendors and devices to support */ +#define VENDOR1 0x1931 /* Vendor Option */ +#define DEVICE1 0x000c /* HSDPA card */ + +#define R_IIR 0x0000 /* Interrupt Identity Register */ +#define R_FCR 0x0000 /* Flow Control Register */ +#define R_IER 0x0004 /* Interrupt Enable Register */ + +#define CONFIG_MAGIC 0xEFEFFEFE +#define TOGGLE_VALID 0x0000 + +/* Definition of interrupt tokens */ +#define MDM_DL1 0x0001 +#define MDM_UL1 0x0002 +#define MDM_DL2 0x0004 +#define MDM_UL2 0x0008 +#define DIAG_DL1 0x0010 +#define DIAG_DL2 0x0020 +#define DIAG_UL 0x0040 +#define APP1_DL 0x0080 +#define APP1_UL 0x0100 +#define APP2_DL 0x0200 +#define APP2_UL 0x0400 +#define CTRL_DL 0x0800 +#define CTRL_UL 0x1000 +#define RESET 0x8000 + +#define MDM_DL (MDM_DL1 | MDM_DL2) +#define MDM_UL (MDM_UL1 | MDM_UL2) +#define DIAG_DL (DIAG_DL1 | DIAG_DL2) + +/* modem signal definition */ +#define CTRL_DSR 0x0001 +#define CTRL_DCD 0x0002 +#define CTRL_RI 0x0004 +#define CTRL_CTS 0x0008 + +#define CTRL_DTR 0x0001 +#define CTRL_RTS 0x0002 + +#define MAX_PORT 4 +#define NOZOMI_MAX_PORTS 5 +#define NOZOMI_MAX_CARDS (NTTY_TTY_MAXMINORS / MAX_PORT) + +/* Type definitions */ + +/* + * There are two types of nozomi cards, + * one with 2048 memory and with 8192 memory + */ +enum card_type { + F32_2 = 2048, /* 512 bytes downlink + uplink * 2 -> 2048 */ + F32_8 = 8192, /* 3072 bytes downl. + 1024 bytes uplink * 2 -> 8192 */ +}; + +/* Two different toggle channels exist */ +enum channel_type { + CH_A = 0, + CH_B = 1, +}; + +/* Port definition for the card regarding flow control */ +enum ctrl_port_type { + CTRL_CMD = 0, + CTRL_MDM = 1, + CTRL_DIAG = 2, + CTRL_APP1 = 3, + CTRL_APP2 = 4, + CTRL_ERROR = -1, +}; + +/* Ports that the nozomi has */ +enum port_type { + PORT_MDM = 0, + PORT_DIAG = 1, + PORT_APP1 = 2, + PORT_APP2 = 3, + PORT_CTRL = 4, + PORT_ERROR = -1, +}; + +#ifdef __BIG_ENDIAN +/* Big endian */ + +struct toggles { + unsigned enabled:5; /* + * Toggle fields are valid if enabled is 0, + * else A-channels must always be used. + */ + unsigned diag_dl:1; + unsigned mdm_dl:1; + unsigned mdm_ul:1; +} __attribute__ ((packed)); + +/* Configuration table to read at startup of card */ +/* Is for now only needed during initialization phase */ +struct config_table { + u32 signature; + u16 product_information; + u16 version; + u8 pad3[3]; + struct toggles toggle; + u8 pad1[4]; + u16 dl_mdm_len1; /* + * If this is 64, it can hold + * 60 bytes + 4 that is length field + */ + u16 dl_start; + + u16 dl_diag_len1; + u16 dl_mdm_len2; /* + * If this is 64, it can hold + * 60 bytes + 4 that is length field + */ + u16 dl_app1_len; + + u16 dl_diag_len2; + u16 dl_ctrl_len; + u16 dl_app2_len; + u8 pad2[16]; + u16 ul_mdm_len1; + u16 ul_start; + u16 ul_diag_len; + u16 ul_mdm_len2; + u16 ul_app1_len; + u16 ul_app2_len; + u16 ul_ctrl_len; +} __attribute__ ((packed)); + +/* This stores all control downlink flags */ +struct ctrl_dl { + u8 port; + unsigned reserved:4; + unsigned CTS:1; + unsigned RI:1; + unsigned DCD:1; + unsigned DSR:1; +} __attribute__ ((packed)); + +/* This stores all control uplink flags */ +struct ctrl_ul { + u8 port; + unsigned reserved:6; + unsigned RTS:1; + unsigned DTR:1; +} __attribute__ ((packed)); + +#else +/* Little endian */ + +/* This represents the toggle information */ +struct toggles { + unsigned mdm_ul:1; + unsigned mdm_dl:1; + unsigned diag_dl:1; + unsigned enabled:5; /* + * Toggle fields are valid if enabled is 0, + * else A-channels must always be used. + */ +} __attribute__ ((packed)); + +/* Configuration table to read at startup of card */ +struct config_table { + u32 signature; + u16 version; + u16 product_information; + struct toggles toggle; + u8 pad1[7]; + u16 dl_start; + u16 dl_mdm_len1; /* + * If this is 64, it can hold + * 60 bytes + 4 that is length field + */ + u16 dl_mdm_len2; + u16 dl_diag_len1; + u16 dl_diag_len2; + u16 dl_app1_len; + u16 dl_app2_len; + u16 dl_ctrl_len; + u8 pad2[16]; + u16 ul_start; + u16 ul_mdm_len2; + u16 ul_mdm_len1; + u16 ul_diag_len; + u16 ul_app1_len; + u16 ul_app2_len; + u16 ul_ctrl_len; +} __attribute__ ((packed)); + +/* This stores all control downlink flags */ +struct ctrl_dl { + unsigned DSR:1; + unsigned DCD:1; + unsigned RI:1; + unsigned CTS:1; + unsigned reserverd:4; + u8 port; +} __attribute__ ((packed)); + +/* This stores all control uplink flags */ +struct ctrl_ul { + unsigned DTR:1; + unsigned RTS:1; + unsigned reserved:6; + u8 port; +} __attribute__ ((packed)); +#endif + +/* This holds all information that is needed regarding a port */ +struct port { + u8 update_flow_control; + struct ctrl_ul ctrl_ul; + struct ctrl_dl ctrl_dl; + struct kfifo *fifo_ul; + void __iomem *dl_addr[2]; + u32 dl_size[2]; + u8 toggle_dl; + void __iomem *ul_addr[2]; + u32 ul_size[2]; + u8 toggle_ul; + u16 token_dl; + + struct tty_struct *tty; + int tty_open_count; + /* mutex to ensure one access patch to this port */ + struct mutex tty_sem; + wait_queue_head_t tty_wait; + struct async_icount tty_icount; +}; + +/* Private data one for each card in the system */ +struct nozomi { + void __iomem *base_addr; + unsigned long flip; + + /* Pointers to registers */ + void __iomem *reg_iir; + void __iomem *reg_fcr; + void __iomem *reg_ier; + + u16 last_ier; + enum card_type card_type; + struct config_table config_table; /* Configuration table */ + struct pci_dev *pdev; + struct port port[NOZOMI_MAX_PORTS]; + u8 *send_buf; + + spinlock_t spin_mutex; /* secures access to registers and tty */ + + unsigned int index_start; + u32 open_ttys; +}; + +/* This is a data packet that is read or written to/from card */ +struct buffer { + u32 size; /* size is the length of the data buffer */ + u8 *data; +} __attribute__ ((packed)); + +/* Global variables */ +static struct pci_device_id nozomi_pci_tbl[] = { + {PCI_DEVICE(VENDOR1, DEVICE1)}, + {}, +}; + +MODULE_DEVICE_TABLE(pci, nozomi_pci_tbl); + +static struct nozomi *ndevs[NOZOMI_MAX_CARDS]; +static struct tty_driver *ntty_driver; + +/* + * find card by tty_index + */ +static inline struct nozomi *get_dc_by_tty(const struct tty_struct *tty) +{ + return tty ? ndevs[tty->index / MAX_PORT] : NULL; +} + +static inline struct port *get_port_by_tty(const struct tty_struct *tty) +{ + struct nozomi *ndev = get_dc_by_tty(tty); + return ndev ? &ndev->port[tty->index % MAX_PORT] : NULL; +} + +/* + * TODO: + * -Optimize + * -Rewrite cleaner + */ + +static void read_mem32(u32 *buf, const void __iomem *mem_addr_start, + u32 size_bytes) +{ + u32 i = 0; + const u32 *ptr = (__force u32 *) mem_addr_start; + u16 *buf16; + + if (unlikely(!ptr || !buf)) + goto out; + + /* shortcut for extremely often used cases */ + switch (size_bytes) { + case 2: /* 2 bytes */ + buf16 = (u16 *) buf; + *buf16 = __le16_to_cpu(readw((void __iomem *)ptr)); + goto out; + break; + case 4: /* 4 bytes */ + *(buf) = __le32_to_cpu(readl((void __iomem *)ptr)); + goto out; + break; + } + + while (i < size_bytes) { + if (size_bytes - i == 2) { + /* Handle 2 bytes in the end */ + buf16 = (u16 *) buf; + *(buf16) = __le16_to_cpu(readw((void __iomem *)ptr)); + i += 2; + } else { + /* Read 4 bytes */ + *(buf) = __le32_to_cpu(readl((void __iomem *)ptr)); + i += 4; + } + buf++; + ptr++; + } +out: + return; +} + +/* + * TODO: + * -Optimize + * -Rewrite cleaner + */ +static u32 write_mem32(void __iomem *mem_addr_start, u32 *buf, + u32 size_bytes) +{ + u32 i = 0; + u32 *ptr = (__force u32 *) mem_addr_start; + u16 *buf16; + + if (unlikely(!ptr || !buf)) + return 0; + + /* shortcut for extremely often used cases */ + switch (size_bytes) { + case 2: /* 2 bytes */ + buf16 = (u16 *) buf; + writew(__cpu_to_le16(*buf16), (void __iomem *)ptr); + return 2; + break; + case 1: /* + * also needs to write 4 bytes in this case + * so falling through.. + */ + case 4: /* 4 bytes */ + writel(__cpu_to_le32(*buf), (void __iomem *)ptr); + return 4; + break; + } + + while (i < size_bytes) { + if (size_bytes - i == 2) { + /* 2 bytes */ + buf16 = (u16 *) buf; + writew(__cpu_to_le16(*buf16), (void __iomem *)ptr); + i += 2; + } else { + /* 4 bytes */ + writel(__cpu_to_le32(*buf), (void __iomem *)ptr); + i += 4; + } + buf++; + ptr++; + } + return i; +} + +/* Setup pointers to different channels and also setup buffer sizes. */ +static void setup_memory(struct nozomi *dc) +{ + void __iomem *offset = dc->base_addr + dc->config_table.dl_start; + /* The length reported is including the length field of 4 bytes, + * hence subtract with 4. + */ + const u16 buff_offset = 4; + + /* Modem port dl configuration */ + dc->port[PORT_MDM].dl_addr[CH_A] = offset; + dc->port[PORT_MDM].dl_addr[CH_B] = + (offset += dc->config_table.dl_mdm_len1); + dc->port[PORT_MDM].dl_size[CH_A] = + dc->config_table.dl_mdm_len1 - buff_offset; + dc->port[PORT_MDM].dl_size[CH_B] = + dc->config_table.dl_mdm_len2 - buff_offset; + + /* Diag port dl configuration */ + dc->port[PORT_DIAG].dl_addr[CH_A] = + (offset += dc->config_table.dl_mdm_len2); + dc->port[PORT_DIAG].dl_size[CH_A] = + dc->config_table.dl_diag_len1 - buff_offset; + dc->port[PORT_DIAG].dl_addr[CH_B] = + (offset += dc->config_table.dl_diag_len1); + dc->port[PORT_DIAG].dl_size[CH_B] = + dc->config_table.dl_diag_len2 - buff_offset; + + /* App1 port dl configuration */ + dc->port[PORT_APP1].dl_addr[CH_A] = + (offset += dc->config_table.dl_diag_len2); + dc->port[PORT_APP1].dl_size[CH_A] = + dc->config_table.dl_app1_len - buff_offset; + + /* App2 port dl configuration */ + dc->port[PORT_APP2].dl_addr[CH_A] = + (offset += dc->config_table.dl_app1_len); + dc->port[PORT_APP2].dl_size[CH_A] = + dc->config_table.dl_app2_len - buff_offset; + + /* Ctrl dl configuration */ + dc->port[PORT_CTRL].dl_addr[CH_A] = + (offset += dc->config_table.dl_app2_len); + dc->port[PORT_CTRL].dl_size[CH_A] = + dc->config_table.dl_ctrl_len - buff_offset; + + offset = dc->base_addr + dc->config_table.ul_start; + + /* Modem Port ul configuration */ + dc->port[PORT_MDM].ul_addr[CH_A] = offset; + dc->port[PORT_MDM].ul_size[CH_A] = + dc->config_table.ul_mdm_len1 - buff_offset; + dc->port[PORT_MDM].ul_addr[CH_B] = + (offset += dc->config_table.ul_mdm_len1); + dc->port[PORT_MDM].ul_size[CH_B] = + dc->config_table.ul_mdm_len2 - buff_offset; + + /* Diag port ul configuration */ + dc->port[PORT_DIAG].ul_addr[CH_A] = + (offset += dc->config_table.ul_mdm_len2); + dc->port[PORT_DIAG].ul_size[CH_A] = + dc->config_table.ul_diag_len - buff_offset; + + /* App1 port ul configuration */ + dc->port[PORT_APP1].ul_addr[CH_A] = + (offset += dc->config_table.ul_diag_len); + dc->port[PORT_APP1].ul_size[CH_A] = + dc->config_table.ul_app1_len - buff_offset; + + /* App2 port ul configuration */ + dc->port[PORT_APP2].ul_addr[CH_A] = + (offset += dc->config_table.ul_app1_len); + dc->port[PORT_APP2].ul_size[CH_A] = + dc->config_table.ul_app2_len - buff_offset; + + /* Ctrl ul configuration */ + dc->port[PORT_CTRL].ul_addr[CH_A] = + (offset += dc->config_table.ul_app2_len); + dc->port[PORT_CTRL].ul_size[CH_A] = + dc->config_table.ul_ctrl_len - buff_offset; +} + +/* Dump config table under initalization phase */ +#ifdef DEBUG +static void dump_table(const struct nozomi *dc) +{ + DBG3("signature: 0x%08X", dc->config_table.signature); + DBG3("version: 0x%04X", dc->config_table.version); + DBG3("product_information: 0x%04X", \ + dc->config_table.product_information); + DBG3("toggle enabled: %d", dc->config_table.toggle.enabled); + DBG3("toggle up_mdm: %d", dc->config_table.toggle.mdm_ul); + DBG3("toggle dl_mdm: %d", dc->config_table.toggle.mdm_dl); + DBG3("toggle dl_dbg: %d", dc->config_table.toggle.diag_dl); + + DBG3("dl_start: 0x%04X", dc->config_table.dl_start); + DBG3("dl_mdm_len0: 0x%04X, %d", dc->config_table.dl_mdm_len1, + dc->config_table.dl_mdm_len1); + DBG3("dl_mdm_len1: 0x%04X, %d", dc->config_table.dl_mdm_len2, + dc->config_table.dl_mdm_len2); + DBG3("dl_diag_len0: 0x%04X, %d", dc->config_table.dl_diag_len1, + dc->config_table.dl_diag_len1); + DBG3("dl_diag_len1: 0x%04X, %d", dc->config_table.dl_diag_len2, + dc->config_table.dl_diag_len2); + DBG3("dl_app1_len: 0x%04X, %d", dc->config_table.dl_app1_len, + dc->config_table.dl_app1_len); + DBG3("dl_app2_len: 0x%04X, %d", dc->config_table.dl_app2_len, + dc->config_table.dl_app2_len); + DBG3("dl_ctrl_len: 0x%04X, %d", dc->config_table.dl_ctrl_len, + dc->config_table.dl_ctrl_len); + DBG3("ul_start: 0x%04X, %d", dc->config_table.ul_start, + dc->config_table.ul_start); + DBG3("ul_mdm_len[0]: 0x%04X, %d", dc->config_table.ul_mdm_len1, + dc->config_table.ul_mdm_len1); + DBG3("ul_mdm_len[1]: 0x%04X, %d", dc->config_table.ul_mdm_len2, + dc->config_table.ul_mdm_len2); + DBG3("ul_diag_len: 0x%04X, %d", dc->config_table.ul_diag_len, + dc->config_table.ul_diag_len); + DBG3("ul_app1_len: 0x%04X, %d", dc->config_table.ul_app1_len, + dc->config_table.ul_app1_len); + DBG3("ul_app2_len: 0x%04X, %d", dc->config_table.ul_app2_len, + dc->config_table.ul_app2_len); + DBG3("ul_ctrl_len: 0x%04X, %d", dc->config_table.ul_ctrl_len, + dc->config_table.ul_ctrl_len); +} +#else +static __inline__ void dump_table(const struct nozomi *dc) { } +#endif + +/* + * Read configuration table from card under intalization phase + * Returns 1 if ok, else 0 + */ +static int nozomi_read_config_table(struct nozomi *dc) +{ + read_mem32((u32 *) &dc->config_table, dc->base_addr + 0, + sizeof(struct config_table)); + + if (dc->config_table.signature != CONFIG_MAGIC) { + dev_err(&dc->pdev->dev, "ConfigTable Bad! 0x%08X != 0x%08X\n", + dc->config_table.signature, CONFIG_MAGIC); + return 0; + } + + if ((dc->config_table.version == 0) + || (dc->config_table.toggle.enabled == TOGGLE_VALID)) { + int i; + DBG1("Second phase, configuring card"); + + setup_memory(dc); + + dc->port[PORT_MDM].toggle_ul = dc->config_table.toggle.mdm_ul; + dc->port[PORT_MDM].toggle_dl = dc->config_table.toggle.mdm_dl; + dc->port[PORT_DIAG].toggle_dl = dc->config_table.toggle.diag_dl; + DBG1("toggle ports: MDM UL:%d MDM DL:%d, DIAG DL:%d", + dc->port[PORT_MDM].toggle_ul, + dc->port[PORT_MDM].toggle_dl, dc->port[PORT_DIAG].toggle_dl); + + dump_table(dc); + + for (i = PORT_MDM; i < MAX_PORT; i++) { + dc->port[i].fifo_ul = + kfifo_alloc(FIFO_BUFFER_SIZE_UL, GFP_ATOMIC, NULL); + memset(&dc->port[i].ctrl_dl, 0, sizeof(struct ctrl_dl)); + memset(&dc->port[i].ctrl_ul, 0, sizeof(struct ctrl_ul)); + } + + /* Enable control channel */ + dc->last_ier = dc->last_ier | CTRL_DL; + writew(dc->last_ier, dc->reg_ier); + + dev_info(&dc->pdev->dev, "Initialization OK!\n"); + return 1; + } + + if ((dc->config_table.version > 0) + && (dc->config_table.toggle.enabled != TOGGLE_VALID)) { + u32 offset = 0; + DBG1("First phase: pushing upload buffers, clearing download"); + + dev_info(&dc->pdev->dev, "Version of card: %d\n", + dc->config_table.version); + + /* Here we should disable all I/O over F32. */ + setup_memory(dc); + + /* + * We should send ALL channel pair tokens back along + * with reset token + */ + + /* push upload modem buffers */ + write_mem32(dc->port[PORT_MDM].ul_addr[CH_A], + (u32 *) &offset, 4); + write_mem32(dc->port[PORT_MDM].ul_addr[CH_B], + (u32 *) &offset, 4); + + writew(MDM_UL | DIAG_DL | MDM_DL, dc->reg_fcr); + + DBG1("First phase done"); + } + + return 1; +} + +/* Enable uplink interrupts */ +static void enable_transmit_ul(enum port_type port, struct nozomi *dc) +{ + u16 mask[NOZOMI_MAX_PORTS] = \ + {MDM_UL, DIAG_UL, APP1_UL, APP2_UL, CTRL_UL}; + + if (port < NOZOMI_MAX_PORTS) { + dc->last_ier |= mask[port]; + writew(dc->last_ier, dc->reg_ier); + } else { + dev_err(&dc->pdev->dev, "Called with wrong port?\n"); + } +} + +/* Disable uplink interrupts */ +static void disable_transmit_ul(enum port_type port, struct nozomi *dc) +{ + u16 mask[NOZOMI_MAX_PORTS] = \ + {~MDM_UL, ~DIAG_UL, ~APP1_UL, ~APP2_UL, ~CTRL_UL}; + + if (port < NOZOMI_MAX_PORTS) { + dc->last_ier &= mask[port]; + writew(dc->last_ier, dc->reg_ier); + } else { + dev_err(&dc->pdev->dev, "Called with wrong port?\n"); + } +} + +/* Enable downlink interrupts */ +static void enable_transmit_dl(enum port_type port, struct nozomi *dc) +{ + u16 mask[NOZOMI_MAX_PORTS] = \ + {MDM_DL, DIAG_DL, APP1_DL, APP2_DL, CTRL_DL}; + + if (port < NOZOMI_MAX_PORTS) { + dc->last_ier |= mask[port]; + writew(dc->last_ier, dc->reg_ier); + } else { + dev_err(&dc->pdev->dev, "Called with wrong port?\n"); + } +} + +/* Disable downlink interrupts */ +static void disable_transmit_dl(enum port_type port, struct nozomi *dc) +{ + u16 mask[NOZOMI_MAX_PORTS] = \ + {~MDM_DL, ~DIAG_DL, ~APP1_DL, ~APP2_DL, ~CTRL_DL}; + + if (port < NOZOMI_MAX_PORTS) { + dc->last_ier &= mask[port]; + writew(dc->last_ier, dc->reg_ier); + } else { + dev_err(&dc->pdev->dev, "Called with wrong port?\n"); + } +} + +/* + * Return 1 - send buffer to card and ack. + * Return 0 - don't ack, don't send buffer to card. + */ +static int send_data(enum port_type index, struct nozomi *dc) +{ + u32 size = 0; + struct port *port = &dc->port[index]; + u8 toggle = port->toggle_ul; + void __iomem *addr = port->ul_addr[toggle]; + u32 ul_size = port->ul_size[toggle]; + struct tty_struct *tty = port->tty; + + /* Get data from tty and place in buf for now */ + size = __kfifo_get(port->fifo_ul, dc->send_buf, + ul_size < SEND_BUF_MAX ? ul_size : SEND_BUF_MAX); + + if (size == 0) { + DBG4("No more data to send, disable link:"); + return 0; + } + + /* DUMP(buf, size); */ + + /* Write length + data */ + write_mem32(addr, (u32 *) &size, 4); + write_mem32(addr + 4, (u32 *) dc->send_buf, size); + + if (tty) + tty_wakeup(tty); + + return 1; +} + +/* If all data has been read, return 1, else 0 */ +static int receive_data(enum port_type index, struct nozomi *dc) +{ + u8 buf[RECEIVE_BUF_MAX] = { 0 }; + int size; + u32 offset = 4; + struct port *port = &dc->port[index]; + void __iomem *addr = port->dl_addr[port->toggle_dl]; + struct tty_struct *tty = port->tty; + int i; + + if (unlikely(!tty)) { + DBG1("tty not open for port: %d?", index); + return 1; + } + + read_mem32((u32 *) &size, addr, 4); + /* DBG1( "%d bytes port: %d", size, index); */ + + if (test_bit(TTY_THROTTLED, &tty->flags)) { + DBG1("No room in tty, don't read data, don't ack interrupt, " + "disable interrupt"); + + /* disable interrupt in downlink... */ + disable_transmit_dl(index, dc); + return 0; + } + + if (unlikely(size == 0)) { + dev_err(&dc->pdev->dev, "size == 0?\n"); + return 1; + } + + tty_buffer_request_room(tty, size); + + while (size > 0) { + read_mem32((u32 *) buf, addr + offset, RECEIVE_BUF_MAX); + + if (size == 1) { + tty_insert_flip_char(tty, buf[0], TTY_NORMAL); + size = 0; + } else if (size < RECEIVE_BUF_MAX) { + size -= tty_insert_flip_string(tty, (char *) buf, size); + } else { + i = tty_insert_flip_string(tty, \ + (char *) buf, RECEIVE_BUF_MAX); + size -= i; + offset += i; + } + } + + set_bit(index, &dc->flip); + + return 1; +} + +/* Debug for interrupts */ +#ifdef DEBUG +static char *interrupt2str(u16 interrupt) +{ + static char buf[TMP_BUF_MAX]; + char *p = buf; + + interrupt & MDM_DL1 ? p += snprintf(p, TMP_BUF_MAX, "MDM_DL1 ") : NULL; + interrupt & MDM_DL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "MDM_DL2 ") : NULL; + + interrupt & MDM_UL1 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "MDM_UL1 ") : NULL; + interrupt & MDM_UL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "MDM_UL2 ") : NULL; + + interrupt & DIAG_DL1 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "DIAG_DL1 ") : NULL; + interrupt & DIAG_DL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "DIAG_DL2 ") : NULL; + + interrupt & DIAG_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "DIAG_UL ") : NULL; + + interrupt & APP1_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "APP1_DL ") : NULL; + interrupt & APP2_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "APP2_DL ") : NULL; + + interrupt & APP1_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "APP1_UL ") : NULL; + interrupt & APP2_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "APP2_UL ") : NULL; + + interrupt & CTRL_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "CTRL_DL ") : NULL; + interrupt & CTRL_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "CTRL_UL ") : NULL; + + interrupt & RESET ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "RESET ") : NULL; + + return buf; +} +#endif + +/* + * Receive flow control + * Return 1 - If ok, else 0 + */ +static int receive_flow_control(struct nozomi *dc) +{ + enum port_type port = PORT_MDM; + struct ctrl_dl ctrl_dl; + struct ctrl_dl old_ctrl; + u16 enable_ier = 0; + + read_mem32((u32 *) &ctrl_dl, dc->port[PORT_CTRL].dl_addr[CH_A], 2); + + switch (ctrl_dl.port) { + case CTRL_CMD: + DBG1("The Base Band sends this value as a response to a " + "request for IMSI detach sent over the control " + "channel uplink (see section 7.6.1)."); + break; + case CTRL_MDM: + port = PORT_MDM; + enable_ier = MDM_DL; + break; + case CTRL_DIAG: + port = PORT_DIAG; + enable_ier = DIAG_DL; + break; + case CTRL_APP1: + port = PORT_APP1; + enable_ier = APP1_DL; + break; + case CTRL_APP2: + port = PORT_APP2; + enable_ier = APP2_DL; + break; + default: + dev_err(&dc->pdev->dev, + "ERROR: flow control received for non-existing port\n"); + return 0; + }; + + DBG1("0x%04X->0x%04X", *((u16 *)&dc->port[port].ctrl_dl), + *((u16 *)&ctrl_dl)); + + old_ctrl = dc->port[port].ctrl_dl; + dc->port[port].ctrl_dl = ctrl_dl; + + if (old_ctrl.CTS == 1 && ctrl_dl.CTS == 0) { + DBG1("Disable interrupt (0x%04X) on port: %d", + enable_ier, port); + disable_transmit_ul(port, dc); + + } else if (old_ctrl.CTS == 0 && ctrl_dl.CTS == 1) { + + if (__kfifo_len(dc->port[port].fifo_ul)) { + DBG1("Enable interrupt (0x%04X) on port: %d", + enable_ier, port); + DBG1("Data in buffer [%d], enable transmit! ", + __kfifo_len(dc->port[port].fifo_ul)); + enable_transmit_ul(port, dc); + } else { + DBG1("No data in buffer..."); + } + } + + if (*(u16 *)&old_ctrl == *(u16 *)&ctrl_dl) { + DBG1(" No change in mctrl"); + return 1; + } + /* Update statistics */ + if (old_ctrl.CTS != ctrl_dl.CTS) + dc->port[port].tty_icount.cts++; + if (old_ctrl.DSR != ctrl_dl.DSR) + dc->port[port].tty_icount.dsr++; + if (old_ctrl.RI != ctrl_dl.RI) + dc->port[port].tty_icount.rng++; + if (old_ctrl.DCD != ctrl_dl.DCD) + dc->port[port].tty_icount.dcd++; + + wake_up_interruptible(&dc->port[port].tty_wait); + + DBG1("port: %d DCD(%d), CTS(%d), RI(%d), DSR(%d)", + port, + dc->port[port].tty_icount.dcd, dc->port[port].tty_icount.cts, + dc->port[port].tty_icount.rng, dc->port[port].tty_icount.dsr); + + return 1; +} + +static enum ctrl_port_type port2ctrl(enum port_type port, + const struct nozomi *dc) +{ + switch (port) { + case PORT_MDM: + return CTRL_MDM; + case PORT_DIAG: + return CTRL_DIAG; + case PORT_APP1: + return CTRL_APP1; + case PORT_APP2: + return CTRL_APP2; + default: + dev_err(&dc->pdev->dev, + "ERROR: send flow control " \ + "received for non-existing port\n"); + }; + return CTRL_ERROR; +} + +/* + * Send flow control, can only update one channel at a time + * Return 0 - If we have updated all flow control + * Return 1 - If we need to update more flow control, ack current enable more + */ +static int send_flow_control(struct nozomi *dc) +{ + u32 i, more_flow_control_to_be_updated = 0; + u16 *ctrl; + + for (i = PORT_MDM; i < MAX_PORT; i++) { + if (dc->port[i].update_flow_control) { + if (more_flow_control_to_be_updated) { + /* We have more flow control to be updated */ + return 1; + } + dc->port[i].ctrl_ul.port = port2ctrl(i, dc); + ctrl = (u16 *)&dc->port[i].ctrl_ul; + write_mem32(dc->port[PORT_CTRL].ul_addr[0], \ + (u32 *) ctrl, 2); + dc->port[i].update_flow_control = 0; + more_flow_control_to_be_updated = 1; + } + } + return 0; +} + +/* + * Handle donlink data, ports that are handled are modem and diagnostics + * Return 1 - ok + * Return 0 - toggle fields are out of sync + */ +static int handle_data_dl(struct nozomi *dc, enum port_type port, u8 *toggle, + u16 read_iir, u16 mask1, u16 mask2) +{ + if (*toggle == 0 && read_iir & mask1) { + if (receive_data(port, dc)) { + writew(mask1, dc->reg_fcr); + *toggle = !(*toggle); + } + + if (read_iir & mask2) { + if (receive_data(port, dc)) { + writew(mask2, dc->reg_fcr); + *toggle = !(*toggle); + } + } + } else if (*toggle == 1 && read_iir & mask2) { + if (receive_data(port, dc)) { + writew(mask2, dc->reg_fcr); + *toggle = !(*toggle); + } + + if (read_iir & mask1) { + if (receive_data(port, dc)) { + writew(mask1, dc->reg_fcr); + *toggle = !(*toggle); + } + } + } else { + dev_err(&dc->pdev->dev, "port out of sync!, toggle:%d\n", + *toggle); + return 0; + } + return 1; +} + +/* + * Handle uplink data, this is currently for the modem port + * Return 1 - ok + * Return 0 - toggle field are out of sync + */ +static int handle_data_ul(struct nozomi *dc, enum port_type port, u16 read_iir) +{ + u8 *toggle = &(dc->port[port].toggle_ul); + + if (*toggle == 0 && read_iir & MDM_UL1) { + dc->last_ier &= ~MDM_UL; + writew(dc->last_ier, dc->reg_ier); + if (send_data(port, dc)) { + writew(MDM_UL1, dc->reg_fcr); + dc->last_ier = dc->last_ier | MDM_UL; + writew(dc->last_ier, dc->reg_ier); + *toggle = !*toggle; + } + + if (read_iir & MDM_UL2) { + dc->last_ier &= ~MDM_UL; + writew(dc->last_ier, dc->reg_ier); + if (send_data(port, dc)) { + writew(MDM_UL2, dc->reg_fcr); + dc->last_ier = dc->last_ier | MDM_UL; + writew(dc->last_ier, dc->reg_ier); + *toggle = !*toggle; + } + } + + } else if (*toggle == 1 && read_iir & MDM_UL2) { + dc->last_ier &= ~MDM_UL; + writew(dc->last_ier, dc->reg_ier); + if (send_data(port, dc)) { + writew(MDM_UL2, dc->reg_fcr); + dc->last_ier = dc->last_ier | MDM_UL; + writew(dc->last_ier, dc->reg_ier); + *toggle = !*toggle; + } + + if (read_iir & MDM_UL1) { + dc->last_ier &= ~MDM_UL; + writew(dc->last_ier, dc->reg_ier); + if (send_data(port, dc)) { + writew(MDM_UL1, dc->reg_fcr); + dc->last_ier = dc->last_ier | MDM_UL; + writew(dc->last_ier, dc->reg_ier); + *toggle = !*toggle; + } + } + } else { + writew(read_iir & MDM_UL, dc->reg_fcr); + dev_err(&dc->pdev->dev, "port out of sync!\n"); + return 0; + } + return 1; +} + +static irqreturn_t interrupt_handler(int irq, void *dev_id) +{ + struct nozomi *dc = dev_id; + unsigned int a; + u16 read_iir; + + if (!dc) + return IRQ_NONE; + + spin_lock(&dc->spin_mutex); + read_iir = readw(dc->reg_iir); + + /* Card removed */ + if (read_iir == (u16)-1) + goto none; + /* + * Just handle interrupt enabled in IER + * (by masking with dc->last_ier) + */ + read_iir &= dc->last_ier; + + if (read_iir == 0) + goto none; + + + DBG4("%s irq:0x%04X, prev:0x%04X", interrupt2str(read_iir), read_iir, + dc->last_ier); + + if (read_iir & RESET) { + if (unlikely(!nozomi_read_config_table(dc))) { + dc->last_ier = 0x0; + writew(dc->last_ier, dc->reg_ier); + dev_err(&dc->pdev->dev, "Could not read status from " + "card, we should disable interface\n"); + } else { + writew(RESET, dc->reg_fcr); + } + /* No more useful info if this was the reset interrupt. */ + goto exit_handler; + } + if (read_iir & CTRL_UL) { + DBG1("CTRL_UL"); + dc->last_ier &= ~CTRL_UL; + writew(dc->last_ier, dc->reg_ier); + if (send_flow_control(dc)) { + writew(CTRL_UL, dc->reg_fcr); + dc->last_ier = dc->last_ier | CTRL_UL; + writew(dc->last_ier, dc->reg_ier); + } + } + if (read_iir & CTRL_DL) { + receive_flow_control(dc); + writew(CTRL_DL, dc->reg_fcr); + } + if (read_iir & MDM_DL) { + if (!handle_data_dl(dc, PORT_MDM, + &(dc->port[PORT_MDM].toggle_dl), read_iir, + MDM_DL1, MDM_DL2)) { + dev_err(&dc->pdev->dev, "MDM_DL out of sync!\n"); + goto exit_handler; + } + } + if (read_iir & MDM_UL) { + if (!handle_data_ul(dc, PORT_MDM, read_iir)) { + dev_err(&dc->pdev->dev, "MDM_UL out of sync!\n"); + goto exit_handler; + } + } + if (read_iir & DIAG_DL) { + if (!handle_data_dl(dc, PORT_DIAG, + &(dc->port[PORT_DIAG].toggle_dl), read_iir, + DIAG_DL1, DIAG_DL2)) { + dev_err(&dc->pdev->dev, "DIAG_DL out of sync!\n"); + goto exit_handler; + } + } + if (read_iir & DIAG_UL) { + dc->last_ier &= ~DIAG_UL; + writew(dc->last_ier, dc->reg_ier); + if (send_data(PORT_DIAG, dc)) { + writew(DIAG_UL, dc->reg_fcr); + dc->last_ier = dc->last_ier | DIAG_UL; + writew(dc->last_ier, dc->reg_ier); + } + } + if (read_iir & APP1_DL) { + if (receive_data(PORT_APP1, dc)) + writew(APP1_DL, dc->reg_fcr); + } + if (read_iir & APP1_UL) { + dc->last_ier &= ~APP1_UL; + writew(dc->last_ier, dc->reg_ier); + if (send_data(PORT_APP1, dc)) { + writew(APP1_UL, dc->reg_fcr); + dc->last_ier = dc->last_ier | APP1_UL; + writew(dc->last_ier, dc->reg_ier); + } + } + if (read_iir & APP2_DL) { + if (receive_data(PORT_APP2, dc)) + writew(APP2_DL, dc->reg_fcr); + } + if (read_iir & APP2_UL) { + dc->last_ier &= ~APP2_UL; + writew(dc->last_ier, dc->reg_ier); + if (send_data(PORT_APP2, dc)) { + writew(APP2_UL, dc->reg_fcr); + dc->last_ier = dc->last_ier | APP2_UL; + writew(dc->last_ier, dc->reg_ier); + } + } + +exit_handler: + spin_unlock(&dc->spin_mutex); + for (a = 0; a < NOZOMI_MAX_PORTS; a++) + if (test_and_clear_bit(a, &dc->flip)) + tty_flip_buffer_push(dc->port[a].tty); + return IRQ_HANDLED; +none: + spin_unlock(&dc->spin_mutex); + return IRQ_NONE; +} + +static void nozomi_get_card_type(struct nozomi *dc) +{ + int i; + u32 size = 0; + + for (i = 0; i < 6; i++) + size += pci_resource_len(dc->pdev, i); + + /* Assume card type F32_8 if no match */ + dc->card_type = size == 2048 ? F32_2 : F32_8; + + dev_info(&dc->pdev->dev, "Card type is: %d\n", dc->card_type); +} + +static void nozomi_setup_private_data(struct nozomi *dc) +{ + void __iomem *offset = dc->base_addr + dc->card_type / 2; + unsigned int i; + + dc->reg_fcr = (void __iomem *)(offset + R_FCR); + dc->reg_iir = (void __iomem *)(offset + R_IIR); + dc->reg_ier = (void __iomem *)(offset + R_IER); + dc->last_ier = 0; + dc->flip = 0; + + dc->port[PORT_MDM].token_dl = MDM_DL; + dc->port[PORT_DIAG].token_dl = DIAG_DL; + dc->port[PORT_APP1].token_dl = APP1_DL; + dc->port[PORT_APP2].token_dl = APP2_DL; + + for (i = 0; i < MAX_PORT; i++) + init_waitqueue_head(&dc->port[i].tty_wait); +} + +static ssize_t card_type_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev)); + + return sprintf(buf, "%d\n", dc->card_type); +} +static DEVICE_ATTR(card_type, 0444, card_type_show, NULL); + +static ssize_t open_ttys_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev)); + + return sprintf(buf, "%u\n", dc->open_ttys); +} +static DEVICE_ATTR(open_ttys, 0444, open_ttys_show, NULL); + +static void make_sysfs_files(struct nozomi *dc) +{ + if (device_create_file(&dc->pdev->dev, &dev_attr_card_type)) + dev_err(&dc->pdev->dev, + "Could not create sysfs file for card_type\n"); + if (device_create_file(&dc->pdev->dev, &dev_attr_open_ttys)) + dev_err(&dc->pdev->dev, + "Could not create sysfs file for open_ttys\n"); +} + +static void remove_sysfs_files(struct nozomi *dc) +{ + device_remove_file(&dc->pdev->dev, &dev_attr_card_type); + device_remove_file(&dc->pdev->dev, &dev_attr_open_ttys); +} + +/* Allocate memory for one device */ +static int __devinit nozomi_card_init(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + resource_size_t start; + int ret; + struct nozomi *dc = NULL; + int ndev_idx; + int i; + + dev_dbg(&pdev->dev, "Init, new card found\n"); + + for (ndev_idx = 0; ndev_idx < ARRAY_SIZE(ndevs); ndev_idx++) + if (!ndevs[ndev_idx]) + break; + + if (ndev_idx >= ARRAY_SIZE(ndevs)) { + dev_err(&pdev->dev, "no free tty range for this card left\n"); + ret = -EIO; + goto err; + } + + dc = kzalloc(sizeof(struct nozomi), GFP_KERNEL); + if (unlikely(!dc)) { + dev_err(&pdev->dev, "Could not allocate memory\n"); + ret = -ENOMEM; + goto err_free; + } + + dc->pdev = pdev; + + /* Find out what card type it is */ + nozomi_get_card_type(dc); + + ret = pci_enable_device(dc->pdev); + if (ret) { + dev_err(&pdev->dev, "Failed to enable PCI Device\n"); + goto err_free; + } + + start = pci_resource_start(dc->pdev, 0); + if (start == 0) { + dev_err(&pdev->dev, "No I/O address for card detected\n"); + ret = -ENODEV; + goto err_disable_device; + } + + ret = pci_request_regions(dc->pdev, NOZOMI_NAME); + if (ret) { + dev_err(&pdev->dev, "I/O address 0x%04x already in use\n", + (int) /* nozomi_private.io_addr */ 0); + goto err_disable_device; + } + + dc->base_addr = ioremap(start, dc->card_type); + if (!dc->base_addr) { + dev_err(&pdev->dev, "Unable to map card MMIO\n"); + ret = -ENODEV; + goto err_rel_regs; + } + + dc->send_buf = kmalloc(SEND_BUF_MAX, GFP_KERNEL); + if (!dc->send_buf) { + dev_err(&pdev->dev, "Could not allocate send buffer?\n"); + ret = -ENOMEM; + goto err_free_sbuf; + } + + spin_lock_init(&dc->spin_mutex); + + nozomi_setup_private_data(dc); + + /* Disable all interrupts */ + dc->last_ier = 0; + writew(dc->last_ier, dc->reg_ier); + + ret = request_irq(pdev->irq, &interrupt_handler, IRQF_SHARED, + NOZOMI_NAME, dc); + if (unlikely(ret)) { + dev_err(&pdev->dev, "can't request irq %d\n", pdev->irq); + goto err_free_sbuf; + } + + DBG1("base_addr: %p", dc->base_addr); + + make_sysfs_files(dc); + + dc->index_start = ndev_idx * MAX_PORT; + ndevs[ndev_idx] = dc; + + for (i = 0; i < MAX_PORT; i++) { + mutex_init(&dc->port[i].tty_sem); + dc->port[i].tty_open_count = 0; + dc->port[i].tty = NULL; + tty_register_device(ntty_driver, dc->index_start + i, + &pdev->dev); + } + + /* Enable RESET interrupt. */ + dc->last_ier = RESET; + writew(dc->last_ier, dc->reg_ier); + + pci_set_drvdata(pdev, dc); + + return 0; + +err_free_sbuf: + kfree(dc->send_buf); + iounmap(dc->base_addr); +err_rel_regs: + pci_release_regions(pdev); +err_disable_device: + pci_disable_device(pdev); +err_free: + kfree(dc); +err: + return ret; +} + +static void __devexit tty_exit(struct nozomi *dc) +{ + unsigned int i; + + DBG1(" "); + + flush_scheduled_work(); + + for (i = 0; i < MAX_PORT; ++i) + if (dc->port[i].tty && \ + list_empty(&dc->port[i].tty->hangup_work.entry)) + tty_hangup(dc->port[i].tty); + + while (dc->open_ttys) + msleep(1); + + for (i = dc->index_start; i < dc->index_start + MAX_PORT; ++i) + tty_unregister_device(ntty_driver, i); +} + +/* Deallocate memory for one device */ +static void __devexit nozomi_card_exit(struct pci_dev *pdev) +{ + int i; + struct ctrl_ul ctrl; + struct nozomi *dc = pci_get_drvdata(pdev); + + /* Disable all interrupts */ + dc->last_ier = 0; + writew(dc->last_ier, dc->reg_ier); + + tty_exit(dc); + + /* Send 0x0001, command card to resend the reset token. */ + /* This is to get the reset when the module is reloaded. */ + ctrl.port = 0x00; + ctrl.reserved = 0; + ctrl.RTS = 0; + ctrl.DTR = 1; + DBG1("sending flow control 0x%04X", *((u16 *)&ctrl)); + + /* Setup dc->reg addresses to we can use defines here */ + write_mem32(dc->port[PORT_CTRL].ul_addr[0], (u32 *)&ctrl, 2); + writew(CTRL_UL, dc->reg_fcr); /* push the token to the card. */ + + remove_sysfs_files(dc); + + free_irq(pdev->irq, dc); + + for (i = 0; i < MAX_PORT; i++) + if (dc->port[i].fifo_ul) + kfifo_free(dc->port[i].fifo_ul); + + kfree(dc->send_buf); + + iounmap(dc->base_addr); + + pci_release_regions(pdev); + + pci_disable_device(pdev); + + ndevs[dc->index_start / MAX_PORT] = NULL; + + kfree(dc); +} + +static void set_rts(const struct tty_struct *tty, int rts) +{ + struct port *port = get_port_by_tty(tty); + + port->ctrl_ul.RTS = rts; + port->update_flow_control = 1; + enable_transmit_ul(PORT_CTRL, get_dc_by_tty(tty)); +} + +static void set_dtr(const struct tty_struct *tty, int dtr) +{ + struct port *port = get_port_by_tty(tty); + + DBG1("SETTING DTR index: %d, dtr: %d", tty->index, dtr); + + port->ctrl_ul.DTR = dtr; + port->update_flow_control = 1; + enable_transmit_ul(PORT_CTRL, get_dc_by_tty(tty)); +} + +/* + * ---------------------------------------------------------------------------- + * TTY code + * ---------------------------------------------------------------------------- + */ + +/* Called when the userspace process opens the tty, /dev/noz*. */ +static int ntty_open(struct tty_struct *tty, struct file *file) +{ + struct port *port = get_port_by_tty(tty); + struct nozomi *dc = get_dc_by_tty(tty); + unsigned long flags; + + if (!port || !dc) + return -ENODEV; + + if (mutex_lock_interruptible(&port->tty_sem)) + return -ERESTARTSYS; + + port->tty_open_count++; + dc->open_ttys++; + + /* Enable interrupt downlink for channel */ + if (port->tty_open_count == 1) { + tty->low_latency = 1; + tty->driver_data = port; + port->tty = tty; + DBG1("open: %d", port->token_dl); + spin_lock_irqsave(&dc->spin_mutex, flags); + dc->last_ier = dc->last_ier | port->token_dl; + writew(dc->last_ier, dc->reg_ier); + spin_unlock_irqrestore(&dc->spin_mutex, flags); + } + + mutex_unlock(&port->tty_sem); + + return 0; +} + +/* Called when the userspace process close the tty, /dev/noz*. */ +static void ntty_close(struct tty_struct *tty, struct file *file) +{ + struct nozomi *dc = get_dc_by_tty(tty); + struct port *port = tty->driver_data; + unsigned long flags; + + if (!dc || !port) + return; + + if (mutex_lock_interruptible(&port->tty_sem)) + return; + + if (!port->tty_open_count) + goto exit; + + dc->open_ttys--; + port->tty_open_count--; + + if (port->tty_open_count == 0) { + DBG1("close: %d", port->token_dl); + spin_lock_irqsave(&dc->spin_mutex, flags); + dc->last_ier &= ~(port->token_dl); + writew(dc->last_ier, dc->reg_ier); + spin_unlock_irqrestore(&dc->spin_mutex, flags); + } + +exit: + mutex_unlock(&port->tty_sem); +} + +/* + * called when the userspace process writes to the tty (/dev/noz*). + * Data is inserted into a fifo, which is then read and transfered to the modem. + */ +static int ntty_write(struct tty_struct *tty, const unsigned char *buffer, + int count) +{ + int rval = -EINVAL; + struct nozomi *dc = get_dc_by_tty(tty); + struct port *port = tty->driver_data; + unsigned long flags; + + /* DBG1( "WRITEx: %d, index = %d", count, index); */ + + if (!dc || !port) + return -ENODEV; + + if (unlikely(!mutex_trylock(&port->tty_sem))) { + /* + * must test lock as tty layer wraps calls + * to this function with BKL + */ + dev_err(&dc->pdev->dev, "Would have deadlocked - " + "return EAGAIN\n"); + return -EAGAIN; + } + + if (unlikely(!port->tty_open_count)) { + DBG1(" "); + goto exit; + } + + rval = __kfifo_put(port->fifo_ul, (unsigned char *)buffer, count); + + /* notify card */ + if (unlikely(dc == NULL)) { + DBG1("No device context?"); + goto exit; + } + + spin_lock_irqsave(&dc->spin_mutex, flags); + /* CTS is only valid on the modem channel */ + if (port == &(dc->port[PORT_MDM])) { + if (port->ctrl_dl.CTS) { + DBG4("Enable interrupt"); + enable_transmit_ul(tty->index % MAX_PORT, dc); + } else { + dev_err(&dc->pdev->dev, + "CTS not active on modem port?\n"); + } + } else { + enable_transmit_ul(tty->index % MAX_PORT, dc); + } + spin_unlock_irqrestore(&dc->spin_mutex, flags); + +exit: + mutex_unlock(&port->tty_sem); + return rval; +} + +/* + * Calculate how much is left in device + * This method is called by the upper tty layer. + * #according to sources N_TTY.c it expects a value >= 0 and + * does not check for negative values. + */ +static int ntty_write_room(struct tty_struct *tty) +{ + struct port *port = tty->driver_data; + int room = 0; + struct nozomi *dc = get_dc_by_tty(tty); + + if (!dc || !port) + return 0; + if (!mutex_trylock(&port->tty_sem)) + return 0; + + if (!port->tty_open_count) + goto exit; + + room = port->fifo_ul->size - __kfifo_len(port->fifo_ul); + +exit: + mutex_unlock(&port->tty_sem); + return room; +} + +/* Gets io control parameters */ +static int ntty_tiocmget(struct tty_struct *tty, struct file *file) +{ + struct port *port = tty->driver_data; + struct ctrl_dl *ctrl_dl = &port->ctrl_dl; + struct ctrl_ul *ctrl_ul = &port->ctrl_ul; + + return (ctrl_ul->RTS ? TIOCM_RTS : 0) | + (ctrl_ul->DTR ? TIOCM_DTR : 0) | + (ctrl_dl->DCD ? TIOCM_CAR : 0) | + (ctrl_dl->RI ? TIOCM_RNG : 0) | + (ctrl_dl->DSR ? TIOCM_DSR : 0) | + (ctrl_dl->CTS ? TIOCM_CTS : 0); +} + +/* Sets io controls parameters */ +static int ntty_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear) +{ + if (set & TIOCM_RTS) + set_rts(tty, 1); + else if (clear & TIOCM_RTS) + set_rts(tty, 0); + + if (set & TIOCM_DTR) + set_dtr(tty, 1); + else if (clear & TIOCM_DTR) + set_dtr(tty, 0); + + return 0; +} + +static int ntty_cflags_changed(struct port *port, unsigned long flags, + struct async_icount *cprev) +{ + struct async_icount cnow = port->tty_icount; + int ret; + + ret = ((flags & TIOCM_RNG) && (cnow.rng != cprev->rng)) || + ((flags & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) || + ((flags & TIOCM_CD) && (cnow.dcd != cprev->dcd)) || + ((flags & TIOCM_CTS) && (cnow.cts != cprev->cts)); + + *cprev = cnow; + + return ret; +} + +static int ntty_ioctl_tiocgicount(struct port *port, void __user *argp) +{ + struct async_icount cnow = port->tty_icount; + struct serial_icounter_struct icount; + + icount.cts = cnow.cts; + icount.dsr = cnow.dsr; + icount.rng = cnow.rng; + icount.dcd = cnow.dcd; + icount.rx = cnow.rx; + icount.tx = cnow.tx; + icount.frame = cnow.frame; + icount.overrun = cnow.overrun; + icount.parity = cnow.parity; + icount.brk = cnow.brk; + icount.buf_overrun = cnow.buf_overrun; + + return copy_to_user(argp, &icount, sizeof(icount)); +} + +static int ntty_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct port *port = tty->driver_data; + void __user *argp = (void __user *)arg; + int rval = -ENOIOCTLCMD; + + DBG1("******** IOCTL, cmd: %d", cmd); + + switch (cmd) { + case TIOCMIWAIT: { + struct async_icount cprev = port->tty_icount; + + rval = wait_event_interruptible(port->tty_wait, + ntty_cflags_changed(port, arg, &cprev)); + break; + } case TIOCGICOUNT: + rval = ntty_ioctl_tiocgicount(port, argp); + break; + default: + DBG1("ERR: 0x%08X, %d", cmd, cmd); + break; + }; + + return rval; +} + +/* + * Called by the upper tty layer when tty buffers are ready + * to receive data again after a call to throttle. + */ +static void ntty_unthrottle(struct tty_struct *tty) +{ + struct nozomi *dc = get_dc_by_tty(tty); + unsigned long flags; + + DBG1("UNTHROTTLE"); + spin_lock_irqsave(&dc->spin_mutex, flags); + enable_transmit_dl(tty->index % MAX_PORT, dc); + set_rts(tty, 1); + + spin_unlock_irqrestore(&dc->spin_mutex, flags); +} + +/* + * Called by the upper tty layer when the tty buffers are almost full. + * The driver should stop send more data. + */ +static void ntty_throttle(struct tty_struct *tty) +{ + struct nozomi *dc = get_dc_by_tty(tty); + unsigned long flags; + + DBG1("THROTTLE"); + spin_lock_irqsave(&dc->spin_mutex, flags); + set_rts(tty, 0); + spin_unlock_irqrestore(&dc->spin_mutex, flags); +} + +/* just to discard single character writes */ +static void ntty_put_char(struct tty_struct *tty, unsigned char c) +{ + /* FIXME !!! */ + DBG2("PUT CHAR Function: %c", c); +} + +/* Returns number of chars in buffer, called by tty layer */ +static s32 ntty_chars_in_buffer(struct tty_struct *tty) +{ + struct port *port = tty->driver_data; + struct nozomi *dc = get_dc_by_tty(tty); + s32 rval; + + if (unlikely(!dc || !port)) { + rval = -ENODEV; + goto exit_in_buffer; + } + + if (unlikely(!port->tty_open_count)) { + dev_err(&dc->pdev->dev, "No tty open?\n"); + rval = -ENODEV; + goto exit_in_buffer; + } + + rval = __kfifo_len(port->fifo_ul); + +exit_in_buffer: + return rval; +} + +static struct tty_operations tty_ops = { + .ioctl = ntty_ioctl, + .open = ntty_open, + .close = ntty_close, + .write = ntty_write, + .write_room = ntty_write_room, + .unthrottle = ntty_unthrottle, + .throttle = ntty_throttle, + .chars_in_buffer = ntty_chars_in_buffer, + .put_char = ntty_put_char, + .tiocmget = ntty_tiocmget, + .tiocmset = ntty_tiocmset, +}; + +/* Module initialization */ +static struct pci_driver nozomi_driver = { + .name = NOZOMI_NAME, + .id_table = nozomi_pci_tbl, + .probe = nozomi_card_init, + .remove = __devexit_p(nozomi_card_exit), +}; + +static __init int nozomi_init(void) +{ + int ret; + + printk(KERN_INFO "Initializing %s\n", VERSION_STRING); + + ntty_driver = alloc_tty_driver(NTTY_TTY_MAXMINORS); + if (!ntty_driver) + return -ENOMEM; + + ntty_driver->owner = THIS_MODULE; + ntty_driver->driver_name = NOZOMI_NAME_TTY; + ntty_driver->name = "noz"; + ntty_driver->major = 0; + ntty_driver->type = TTY_DRIVER_TYPE_SERIAL; + ntty_driver->subtype = SERIAL_TYPE_NORMAL; + ntty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; + ntty_driver->init_termios = tty_std_termios; + ntty_driver->init_termios.c_cflag = B115200 | CS8 | CREAD | \ + HUPCL | CLOCAL; + ntty_driver->init_termios.c_ispeed = 115200; + ntty_driver->init_termios.c_ospeed = 115200; + tty_set_operations(ntty_driver, &tty_ops); + + ret = tty_register_driver(ntty_driver); + if (ret) { + printk(KERN_ERR "Nozomi: failed to register ntty driver\n"); + goto free_tty; + } + + ret = pci_register_driver(&nozomi_driver); + if (ret) { + printk(KERN_ERR "Nozomi: can't register pci driver\n"); + goto unr_tty; + } + + return 0; +unr_tty: + tty_unregister_driver(ntty_driver); +free_tty: + put_tty_driver(ntty_driver); + return ret; +} + +static __exit void nozomi_exit(void) +{ + printk(KERN_INFO "Unloading %s\n", DRIVER_DESC); + pci_unregister_driver(&nozomi_driver); + tty_unregister_driver(ntty_driver); + put_tty_driver(ntty_driver); +} + +module_init(nozomi_init); +module_exit(nozomi_exit); + +module_param(debug, int, S_IRUGO | S_IWUSR); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 79581fab82d69464a77cf6c51363cec85fede91f..5efd5550f4ca7a4afcf1a606d29e293eea5b4c9e 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -828,11 +828,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) memcpy(&new_policy, policy, sizeof(struct cpufreq_policy)); /* prepare interface data */ - policy->kobj.parent = &sys_dev->kobj; - policy->kobj.ktype = &ktype_cpufreq; - kobject_set_name(&policy->kobj, "cpufreq"); - - ret = kobject_register(&policy->kobj); + ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, &sys_dev->kobj, + "cpufreq"); if (ret) { unlock_policy_rwsem_write(cpu); goto err_out_driver_exit; @@ -902,6 +899,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) goto err_out_unregister; } + kobject_uevent(&policy->kobj, KOBJ_ADD); module_put(cpufreq_driver->owner); dprintk("initialization complete\n"); cpufreq_debug_enable_ratelimit(); @@ -915,7 +913,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) cpufreq_cpu_data[j] = NULL; spin_unlock_irqrestore(&cpufreq_driver_lock, flags); - kobject_unregister(&policy->kobj); + kobject_put(&policy->kobj); wait_for_completion(&policy->kobj_unregister); err_out_driver_exit: @@ -1032,8 +1030,6 @@ static int __cpufreq_remove_dev (struct sys_device * sys_dev) unlock_policy_rwsem_write(cpu); - kobject_unregister(&data->kobj); - kobject_put(&data->kobj); /* we need to make sure that the underlying kobj is actually diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 0f3515e77d4b5e9a0632ecbb95369962697eae6a..088ea74edd3480d42d883e7e7705e3a1f17af7fa 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -277,7 +277,7 @@ static struct kobj_type ktype_state_cpuidle = { static void inline cpuidle_free_state_kobj(struct cpuidle_device *device, int i) { - kobject_unregister(&device->kobjs[i]->kobj); + kobject_put(&device->kobjs[i]->kobj); wait_for_completion(&device->kobjs[i]->kobj_unregister); kfree(device->kobjs[i]); device->kobjs[i] = NULL; @@ -300,14 +300,13 @@ int cpuidle_add_state_sysfs(struct cpuidle_device *device) kobj->state = &device->states[i]; init_completion(&kobj->kobj_unregister); - kobj->kobj.parent = &device->kobj; - kobj->kobj.ktype = &ktype_state_cpuidle; - kobject_set_name(&kobj->kobj, "state%d", i); - ret = kobject_register(&kobj->kobj); + ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle, &device->kobj, + "state%d", i); if (ret) { kfree(kobj); goto error_state; } + kobject_uevent(&kobj->kobj, KOBJ_ADD); device->kobjs[i] = kobj; } @@ -339,12 +338,14 @@ int cpuidle_add_sysfs(struct sys_device *sysdev) { int cpu = sysdev->id; struct cpuidle_device *dev; + int error; dev = per_cpu(cpuidle_devices, cpu); - dev->kobj.parent = &sysdev->kobj; - dev->kobj.ktype = &ktype_cpuidle; - kobject_set_name(&dev->kobj, "%s", "cpuidle"); - return kobject_register(&dev->kobj); + error = kobject_init_and_add(&dev->kobj, &ktype_cpuidle, &sysdev->kobj, + "cpuidle"); + if (!error) + kobject_uevent(&dev->kobj, KOBJ_ADD); + return error; } /** @@ -357,5 +358,5 @@ void cpuidle_remove_sysfs(struct sys_device *sysdev) struct cpuidle_device *dev; dev = per_cpu(cpuidle_devices, cpu); - kobject_unregister(&dev->kobj); + kobject_put(&dev->kobj); } diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index d59b2f417306f91af453962991c5c681aa20381b..bcf52df303390dbf775ea91cd9ab9e714f3f8178 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -41,12 +41,12 @@ * the definition of dma_event_callback in dmaengine.h. * * Each device has a kref, which is initialized to 1 when the device is - * registered. A kref_get is done for each class_device registered. When the - * class_device is released, the coresponding kref_put is done in the release + * registered. A kref_get is done for each device registered. When the + * device is released, the coresponding kref_put is done in the release * method. Every time one of the device's channels is allocated to a client, * a kref_get occurs. When the channel is freed, the coresponding kref_put * happens. The device's release function does a completion, so - * unregister_device does a remove event, class_device_unregister, a kref_put + * unregister_device does a remove event, device_unregister, a kref_put * for the first reference, then waits on the completion for all other * references to finish. * @@ -77,9 +77,9 @@ static LIST_HEAD(dma_client_list); /* --- sysfs implementation --- */ -static ssize_t show_memcpy_count(struct class_device *cd, char *buf) +static ssize_t show_memcpy_count(struct device *dev, struct device_attribute *attr, char *buf) { - struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev); + struct dma_chan *chan = to_dma_chan(dev); unsigned long count = 0; int i; @@ -89,9 +89,10 @@ static ssize_t show_memcpy_count(struct class_device *cd, char *buf) return sprintf(buf, "%lu\n", count); } -static ssize_t show_bytes_transferred(struct class_device *cd, char *buf) +static ssize_t show_bytes_transferred(struct device *dev, struct device_attribute *attr, + char *buf) { - struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev); + struct dma_chan *chan = to_dma_chan(dev); unsigned long count = 0; int i; @@ -101,9 +102,9 @@ static ssize_t show_bytes_transferred(struct class_device *cd, char *buf) return sprintf(buf, "%lu\n", count); } -static ssize_t show_in_use(struct class_device *cd, char *buf) +static ssize_t show_in_use(struct device *dev, struct device_attribute *attr, char *buf) { - struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev); + struct dma_chan *chan = to_dma_chan(dev); int in_use = 0; if (unlikely(chan->slow_ref) && @@ -119,7 +120,7 @@ static ssize_t show_in_use(struct class_device *cd, char *buf) return sprintf(buf, "%d\n", in_use); } -static struct class_device_attribute dma_class_attrs[] = { +static struct device_attribute dma_attrs[] = { __ATTR(memcpy_count, S_IRUGO, show_memcpy_count, NULL), __ATTR(bytes_transferred, S_IRUGO, show_bytes_transferred, NULL), __ATTR(in_use, S_IRUGO, show_in_use, NULL), @@ -128,16 +129,16 @@ static struct class_device_attribute dma_class_attrs[] = { static void dma_async_device_cleanup(struct kref *kref); -static void dma_class_dev_release(struct class_device *cd) +static void dma_dev_release(struct device *dev) { - struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev); + struct dma_chan *chan = to_dma_chan(dev); kref_put(&chan->device->refcount, dma_async_device_cleanup); } static struct class dma_devclass = { - .name = "dma", - .class_dev_attrs = dma_class_attrs, - .release = dma_class_dev_release, + .name = "dma", + .dev_attrs = dma_attrs, + .dev_release = dma_dev_release, }; /* --- client and device registration --- */ @@ -377,12 +378,12 @@ int dma_async_device_register(struct dma_device *device) continue; chan->chan_id = chancnt++; - chan->class_dev.class = &dma_devclass; - chan->class_dev.dev = NULL; - snprintf(chan->class_dev.class_id, BUS_ID_SIZE, "dma%dchan%d", + chan->dev.class = &dma_devclass; + chan->dev.parent = NULL; + snprintf(chan->dev.bus_id, BUS_ID_SIZE, "dma%dchan%d", device->dev_id, chan->chan_id); - rc = class_device_register(&chan->class_dev); + rc = device_register(&chan->dev); if (rc) { chancnt--; free_percpu(chan->local); @@ -411,7 +412,7 @@ int dma_async_device_register(struct dma_device *device) if (chan->local == NULL) continue; kref_put(&device->refcount, dma_async_device_cleanup); - class_device_unregister(&chan->class_dev); + device_unregister(&chan->dev); chancnt--; free_percpu(chan->local); } @@ -445,7 +446,7 @@ void dma_async_device_unregister(struct dma_device *device) list_for_each_entry(chan, &device->channels, device_node) { dma_clients_notify_removed(chan); - class_device_unregister(&chan->class_dev); + device_unregister(&chan->dev); dma_chan_release(chan); } diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c index 70b837f23c436f88d1c5d8be5d97bbf2745e3c6d..53764577035f3f23d0e073991d368f99b8225479 100644 --- a/drivers/edac/edac_device_sysfs.c +++ b/drivers/edac/edac_device_sysfs.c @@ -246,16 +246,6 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev) /* Init the devices's kobject */ memset(&edac_dev->kobj, 0, sizeof(struct kobject)); - edac_dev->kobj.ktype = &ktype_device_ctrl; - - /* set this new device under the edac_class kobject */ - edac_dev->kobj.parent = &edac_class->kset.kobj; - - /* generate sysfs "..../edac/<name>" */ - debugf4("%s() set name of kobject to: %s\n", __func__, edac_dev->name); - err = kobject_set_name(&edac_dev->kobj, "%s", edac_dev->name); - if (err) - goto err_out; /* Record which module 'owns' this control structure * and bump the ref count of the module @@ -268,12 +258,15 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev) } /* register */ - err = kobject_register(&edac_dev->kobj); + err = kobject_init_and_add(&edac_dev->kobj, &ktype_device_ctrl, + &edac_class->kset.kobj, + "%s", edac_dev->name); if (err) { debugf1("%s()Failed to register '.../edac/%s'\n", __func__, edac_dev->name); goto err_kobj_reg; } + kobject_uevent(&edac_dev->kobj, KOBJ_ADD); /* At this point, to 'free' the control struct, * edac_device_unregister_sysfs_main_kobj() must be used @@ -310,7 +303,7 @@ void edac_device_unregister_sysfs_main_kobj( * a) module_put() this module * b) 'kfree' the memory */ - kobject_unregister(&edac_dev->kobj); + kobject_put(&edac_dev->kobj); } /* edac_dev -> instance information */ @@ -533,12 +526,6 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev, /* init this block's kobject */ memset(&block->kobj, 0, sizeof(struct kobject)); - block->kobj.parent = &instance->kobj; - block->kobj.ktype = &ktype_block_ctrl; - - err = kobject_set_name(&block->kobj, "%s", block->name); - if (err) - return err; /* bump the main kobject's reference count for this controller * and this instance is dependant on the main @@ -550,7 +537,9 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev, } /* Add this block's kobject */ - err = kobject_register(&block->kobj); + err = kobject_init_and_add(&block->kobj, &ktype_block_ctrl, + &instance->kobj, + "%s", block->name); if (err) { debugf1("%s() Failed to register instance '%s'\n", __func__, block->name); @@ -579,12 +568,13 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev, goto err_on_attrib; } } + kobject_uevent(&block->kobj, KOBJ_ADD); return 0; /* Error unwind stack */ err_on_attrib: - kobject_unregister(&block->kobj); + kobject_put(&block->kobj); err_out: return err; @@ -615,7 +605,7 @@ static void edac_device_delete_block(struct edac_device_ctl_info *edac_dev, /* unregister this block's kobject, SEE: * edac_device_ctrl_block_release() callback operation */ - kobject_unregister(&block->kobj); + kobject_put(&block->kobj); } /* instance ctor/dtor code */ @@ -637,15 +627,8 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev, /* Init the instance's kobject */ memset(&instance->kobj, 0, sizeof(struct kobject)); - /* set this new device under the edac_device main kobject */ - instance->kobj.parent = &edac_dev->kobj; - instance->kobj.ktype = &ktype_instance_ctrl; instance->ctl = edac_dev; - err = kobject_set_name(&instance->kobj, "%s", instance->name); - if (err) - goto err_out; - /* bump the main kobject's reference count for this controller * and this instance is dependant on the main */ @@ -655,8 +638,9 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev, goto err_out; } - /* Formally register this instance's kobject */ - err = kobject_register(&instance->kobj); + /* Formally register this instance's kobject under the edac_device */ + err = kobject_init_and_add(&instance->kobj, &ktype_instance_ctrl, + &edac_dev->kobj, "%s", instance->name); if (err != 0) { debugf2("%s() Failed to register instance '%s'\n", __func__, instance->name); @@ -679,6 +663,7 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev, goto err_release_instance_kobj; } } + kobject_uevent(&instance->kobj, KOBJ_ADD); debugf4("%s() Registered instance %d '%s' kobject\n", __func__, idx, instance->name); @@ -687,7 +672,7 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev, /* error unwind stack */ err_release_instance_kobj: - kobject_unregister(&instance->kobj); + kobject_put(&instance->kobj); err_out: return err; @@ -712,7 +697,7 @@ static void edac_device_delete_instance(struct edac_device_ctl_info *edac_dev, /* unregister this instance's kobject, SEE: * edac_device_ctrl_instance_release() for callback operation */ - kobject_unregister(&instance->kobj); + kobject_put(&instance->kobj); } /* diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 3706b2bc0987f8a5a22cc5784054dce95bf17973..9aac88027fb31f8a7398fa33173c396983fd7ad2 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -380,13 +380,6 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci, /* generate ..../edac/mc/mc<id>/csrow<index> */ memset(&csrow->kobj, 0, sizeof(csrow->kobj)); csrow->mci = mci; /* include container up link */ - csrow->kobj.parent = kobj_mci; - csrow->kobj.ktype = &ktype_csrow; - - /* name this instance of csrow<id> */ - err = kobject_set_name(&csrow->kobj, "csrow%d", index); - if (err) - goto err_out; /* bump the mci instance's kobject's ref count */ kobj = kobject_get(&mci->edac_mci_kobj); @@ -396,12 +389,13 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci, } /* Instanstiate the csrow object */ - err = kobject_register(&csrow->kobj); + err = kobject_init_and_add(&csrow->kobj, &ktype_csrow, kobj_mci, + "csrow%d", index); if (err) goto err_release_top_kobj; /* At this point, to release a csrow kobj, one must - * call the kobject_unregister and allow that tear down + * call the kobject_put and allow that tear down * to work the releasing */ @@ -412,11 +406,11 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci, err = edac_create_channel_files(&csrow->kobj, chan); if (err) { /* special case the unregister here */ - kobject_unregister(&csrow->kobj); + kobject_put(&csrow->kobj); goto err_out; } } - + kobject_uevent(&csrow->kobj, KOBJ_ADD); return 0; /* error unwind stack */ @@ -744,7 +738,6 @@ static struct kobj_type ktype_mc_set_attribs = { */ static struct kset mc_kset = { .kobj = {.ktype = &ktype_mc_set_attribs }, - .ktype = &ktype_mci, }; @@ -765,14 +758,6 @@ int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci) /* Init the mci's kobject */ memset(kobj_mci, 0, sizeof(*kobj_mci)); - /* this instance become part of the mc_kset */ - kobj_mci->kset = &mc_kset; - - /* set the name of the mc<id> object */ - err = kobject_set_name(kobj_mci, "mc%d", mci->mc_idx); - if (err) - goto fail_out; - /* Record which module 'owns' this control structure * and bump the ref count of the module */ @@ -784,13 +769,18 @@ int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci) goto fail_out; } + /* this instance become part of the mc_kset */ + kobj_mci->kset = &mc_kset; + /* register the mc<id> kobject to the mc_kset */ - err = kobject_register(kobj_mci); + err = kobject_init_and_add(kobj_mci, &ktype_mci, NULL, + "mc%d", mci->mc_idx); if (err) { debugf1("%s()Failed to register '.../edac/mc%d'\n", __func__, mci->mc_idx); goto kobj_reg_fail; } + kobject_uevent(kobj_mci, KOBJ_ADD); /* At this point, to 'free' the control struct, * edac_mc_unregister_sysfs_main_kobj() must be used @@ -818,7 +808,7 @@ int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci) void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci) { /* delete the kobj from the mc_kset */ - kobject_unregister(&mci->edac_mci_kobj); + kobject_put(&mci->edac_mci_kobj); } #define EDAC_DEVICE_SYMLINK "device" @@ -933,7 +923,7 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) fail1: for (i--; i >= 0; i--) { if (csrow->nr_pages > 0) { - kobject_unregister(&mci->csrows[i].kobj); + kobject_put(&mci->csrows[i].kobj); } } @@ -960,7 +950,7 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) for (i = 0; i < mci->nr_csrows; i++) { if (mci->csrows[i].nr_pages > 0) { debugf0("%s() unreg csrow-%d\n", __func__, i); - kobject_unregister(&mci->csrows[i].kobj); + kobject_put(&mci->csrows[i].kobj); } } @@ -977,7 +967,7 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) debugf0("%s() unregister this mci kobj\n", __func__); /* unregister this instance's kobject */ - kobject_unregister(&mci->edac_mci_kobj); + kobject_put(&mci->edac_mci_kobj); } diff --git a/drivers/edac/edac_module.c b/drivers/edac/edac_module.c index e0c4a4086055ad6f2c00bcaabbc77bd91f531d3a..7e1374afd967256054be17b687954151576d60ae 100644 --- a/drivers/edac/edac_module.c +++ b/drivers/edac/edac_module.c @@ -31,7 +31,7 @@ struct workqueue_struct *edac_workqueue; * need to export to other files in this modules */ static struct sysdev_class edac_class = { - set_kset_name("edac"), + .name = "edac", }; static int edac_class_valid; diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c index 69f5dddabddfcfcb0294e374c42bf70c3104c89f..5b075da9914511ffebcb3f2de1362988957a9c3c 100644 --- a/drivers/edac/edac_pci_sysfs.c +++ b/drivers/edac/edac_pci_sysfs.c @@ -162,14 +162,6 @@ static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx) debugf0("%s()\n", __func__); - /* Set the parent and the instance's ktype */ - pci->kobj.parent = &edac_pci_top_main_kobj; - pci->kobj.ktype = &ktype_pci_instance; - - err = kobject_set_name(&pci->kobj, "pci%d", idx); - if (err) - return err; - /* First bump the ref count on the top main kobj, which will * track the number of PCI instances we have, and thus nest * properly on keeping the module loaded @@ -181,7 +173,8 @@ static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx) } /* And now register this new kobject under the main kobj */ - err = kobject_register(&pci->kobj); + err = kobject_init_and_add(&pci->kobj, &ktype_pci_instance, + &edac_pci_top_main_kobj, "pci%d", idx); if (err != 0) { debugf2("%s() failed to register instance pci%d\n", __func__, idx); @@ -189,6 +182,7 @@ static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx) goto error_out; } + kobject_uevent(&pci->kobj, KOBJ_ADD); debugf1("%s() Register instance 'pci%d' kobject\n", __func__, idx); return 0; @@ -211,7 +205,7 @@ void edac_pci_unregister_sysfs_instance_kobj(struct edac_pci_ctl_info *pci) * function release the main reference count and then * kfree the memory */ - kobject_unregister(&pci->kobj); + kobject_put(&pci->kobj); } /***************************** EDAC PCI sysfs root **********************/ @@ -364,14 +358,6 @@ int edac_pci_main_kobj_setup(void) goto decrement_count_fail; } - /* Need the kobject hook ups, and name setting */ - edac_pci_top_main_kobj.ktype = &ktype_edac_pci_main_kobj; - edac_pci_top_main_kobj.parent = &edac_class->kset.kobj; - - err = kobject_set_name(&edac_pci_top_main_kobj, "pci"); - if (err) - goto decrement_count_fail; - /* Bump the reference count on this module to ensure the * modules isn't unloaded until we deconstruct the top * level main kobj for EDAC PCI @@ -383,23 +369,24 @@ int edac_pci_main_kobj_setup(void) } /* Instanstiate the pci object */ - /* FIXME: maybe new sysdev_create_subdir() */ - err = kobject_register(&edac_pci_top_main_kobj); + err = kobject_init_and_add(&edac_pci_top_main_kobj, &ktype_edac_pci_main_kobj, + &edac_class->kset.kobj, "pci"); if (err) { debugf1("Failed to register '.../edac/pci'\n"); - goto kobject_register_fail; + goto kobject_init_and_add_fail; } /* At this point, to 'release' the top level kobject * for EDAC PCI, then edac_pci_main_kobj_teardown() * must be used, for resources to be cleaned up properly */ + kobject_uevent(&edac_pci_top_main_kobj, KOBJ_ADD); debugf1("Registered '.../edac/pci' kobject\n"); return 0; /* Error unwind statck */ -kobject_register_fail: +kobject_init_and_add_fail: module_put(THIS_MODULE); decrement_count_fail: @@ -424,9 +411,9 @@ static void edac_pci_main_kobj_teardown(void) * main kobj */ if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0) { - debugf0("%s() called kobject_unregister on main kobj\n", + debugf0("%s() called kobject_put on main kobj\n", __func__); - kobject_unregister(&edac_pci_top_main_kobj); + kobject_put(&edac_pci_top_main_kobj); } } diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c index 6942e065e6095d2fe55188843f0f7d4dce36dd2a..d168223db1594b7d351956f14903448548c08e1e 100644 --- a/drivers/firmware/edd.c +++ b/drivers/firmware/edd.c @@ -631,7 +631,7 @@ static struct kobj_type edd_ktype = { .default_attrs = def_attrs, }; -static decl_subsys(edd, &edd_ktype, NULL); +static struct kset *edd_kset; /** @@ -693,7 +693,7 @@ edd_create_symlink_to_pcidev(struct edd_device *edev) static inline void edd_device_unregister(struct edd_device *edev) { - kobject_unregister(&edev->kobj); + kobject_put(&edev->kobj); } static void edd_populate_dir(struct edd_device * edev) @@ -721,12 +721,13 @@ edd_device_register(struct edd_device *edev, int i) if (!edev) return 1; edd_dev_set_info(edev, i); - kobject_set_name(&edev->kobj, "int13_dev%02x", - 0x80 + i); - kobj_set_kset_s(edev,edd_subsys); - error = kobject_register(&edev->kobj); - if (!error) + edev->kobj.kset = edd_kset; + error = kobject_init_and_add(&edev->kobj, &edd_ktype, NULL, + "int13_dev%02x", 0x80 + i); + if (!error) { edd_populate_dir(edev); + kobject_uevent(&edev->kobj, KOBJ_ADD); + } return error; } @@ -755,9 +756,9 @@ edd_init(void) return 1; } - rc = firmware_register(&edd_subsys); - if (rc) - return rc; + edd_kset = kset_create_and_add("edd", NULL, firmware_kobj); + if (!edd_kset) + return -ENOMEM; for (i = 0; i < edd_num_devices() && !rc; i++) { edev = kzalloc(sizeof (*edev), GFP_KERNEL); @@ -773,7 +774,7 @@ edd_init(void) } if (rc) - firmware_unregister(&edd_subsys); + kset_unregister(edd_kset); return rc; } @@ -787,7 +788,7 @@ edd_exit(void) if ((edev = edd_devices[i])) edd_device_unregister(edev); } - firmware_unregister(&edd_subsys); + kset_unregister(edd_kset); } late_initcall(edd_init); diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index 858a7b95933bf21993ddd81d178b17ed3d2cc62d..f4f709d1370bf4b2c0ed0d5517530e8136ce4490 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -129,13 +129,6 @@ struct efivar_attribute { }; -#define EFI_ATTR(_name, _mode, _show, _store) \ -struct subsys_attribute efi_attr_##_name = { \ - .attr = {.name = __stringify(_name), .mode = _mode}, \ - .show = _show, \ - .store = _store, \ -}; - #define EFIVAR_ATTR(_name, _mode, _show, _store) \ struct efivar_attribute efivar_attr_##_name = { \ .attr = {.name = __stringify(_name), .mode = _mode}, \ @@ -143,13 +136,6 @@ struct efivar_attribute efivar_attr_##_name = { \ .store = _store, \ }; -#define VAR_SUBSYS_ATTR(_name, _mode, _show, _store) \ -struct subsys_attribute var_subsys_attr_##_name = { \ - .attr = {.name = __stringify(_name), .mode = _mode}, \ - .show = _show, \ - .store = _store, \ -}; - #define to_efivar_attr(_attr) container_of(_attr, struct efivar_attribute, attr) #define to_efivar_entry(obj) container_of(obj, struct efivar_entry, kobj) @@ -408,21 +394,16 @@ static struct kobj_type efivar_ktype = { .default_attrs = def_attrs, }; -static ssize_t -dummy(struct kset *kset, char *buf) -{ - return -ENODEV; -} - static inline void efivar_unregister(struct efivar_entry *var) { - kobject_unregister(&var->kobj); + kobject_put(&var->kobj); } -static ssize_t -efivar_create(struct kset *kset, const char *buf, size_t count) +static ssize_t efivar_create(struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t pos, size_t count) { struct efi_variable *new_var = (struct efi_variable *)buf; struct efivar_entry *search_efivar, *n; @@ -479,8 +460,9 @@ efivar_create(struct kset *kset, const char *buf, size_t count) return count; } -static ssize_t -efivar_delete(struct kset *kset, const char *buf, size_t count) +static ssize_t efivar_delete(struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t pos, size_t count) { struct efi_variable *del_var = (struct efi_variable *)buf; struct efivar_entry *search_efivar, *n; @@ -537,25 +519,26 @@ efivar_delete(struct kset *kset, const char *buf, size_t count) return count; } -static VAR_SUBSYS_ATTR(new_var, 0200, dummy, efivar_create); -static VAR_SUBSYS_ATTR(del_var, 0200, dummy, efivar_delete); +static struct bin_attribute var_subsys_attr_new_var = { + .attr = {.name = "new_var", .mode = 0200}, + .write = efivar_create, +}; -static struct subsys_attribute *var_subsys_attrs[] = { - &var_subsys_attr_new_var, - &var_subsys_attr_del_var, - NULL, +static struct bin_attribute var_subsys_attr_del_var = { + .attr = {.name = "del_var", .mode = 0200}, + .write = efivar_delete, }; /* * Let's not leave out systab information that snuck into * the efivars driver */ -static ssize_t -systab_read(struct kset *kset, char *buf) +static ssize_t systab_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { char *str = buf; - if (!kset || !buf) + if (!kobj || !buf) return -EINVAL; if (efi.mps != EFI_INVALID_TABLE_ADDR) @@ -576,15 +559,21 @@ systab_read(struct kset *kset, char *buf) return str - buf; } -static EFI_ATTR(systab, 0400, systab_read, NULL); +static struct kobj_attribute efi_attr_systab = + __ATTR(systab, 0400, systab_show, NULL); -static struct subsys_attribute *efi_subsys_attrs[] = { - &efi_attr_systab, +static struct attribute *efi_subsys_attrs[] = { + &efi_attr_systab.attr, NULL, /* maybe more in the future? */ }; -static decl_subsys(vars, &efivar_ktype, NULL); -static decl_subsys(efi, NULL, NULL); +static struct attribute_group efi_subsys_attr_group = { + .attrs = efi_subsys_attrs, +}; + + +static struct kset *vars_kset; +static struct kobject *efi_kobj; /* * efivar_create_sysfs_entry() @@ -628,15 +617,16 @@ efivar_create_sysfs_entry(unsigned long variable_name_size, *(short_name + strlen(short_name)) = '-'; efi_guid_unparse(vendor_guid, short_name + strlen(short_name)); - kobject_set_name(&new_efivar->kobj, "%s", short_name); - kobj_set_kset_s(new_efivar, vars_subsys); - i = kobject_register(&new_efivar->kobj); + new_efivar->kobj.kset = vars_kset; + i = kobject_init_and_add(&new_efivar->kobj, &efivar_ktype, NULL, + "%s", short_name); if (i) { kfree(short_name); kfree(new_efivar); return 1; } + kobject_uevent(&new_efivar->kobj, KOBJ_ADD); kfree(short_name); short_name = NULL; @@ -660,9 +650,8 @@ efivars_init(void) efi_status_t status = EFI_NOT_FOUND; efi_guid_t vendor_guid; efi_char16_t *variable_name; - struct subsys_attribute *attr; unsigned long variable_name_size = 1024; - int i, error = 0; + int error = 0; if (!efi_enabled) return -ENODEV; @@ -676,23 +665,18 @@ efivars_init(void) printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION, EFIVARS_DATE); - /* - * For now we'll register the efi subsys within this driver - */ - - error = firmware_register(&efi_subsys); - - if (error) { - printk(KERN_ERR "efivars: Firmware registration failed with error %d.\n", error); + /* For now we'll register the efi directory at /sys/firmware/efi */ + efi_kobj = kobject_create_and_add("efi", firmware_kobj); + if (!efi_kobj) { + printk(KERN_ERR "efivars: Firmware registration failed.\n"); + error = -ENOMEM; goto out_free; } - kobj_set_kset_s(&vars_subsys, efi_subsys); - - error = subsystem_register(&vars_subsys); - - if (error) { - printk(KERN_ERR "efivars: Subsystem registration failed with error %d.\n", error); + vars_kset = kset_create_and_add("vars", NULL, efi_kobj); + if (!vars_kset) { + printk(KERN_ERR "efivars: Subsystem registration failed.\n"); + error = -ENOMEM; goto out_firmware_unregister; } @@ -727,28 +711,28 @@ efivars_init(void) * Now add attributes to allow creation of new vars * and deletion of existing ones... */ - - for (i = 0; (attr = var_subsys_attrs[i]) && !error; i++) { - if (attr->show && attr->store) - error = subsys_create_file(&vars_subsys, attr); - } + error = sysfs_create_bin_file(&vars_kset->kobj, + &var_subsys_attr_new_var); + if (error) + printk(KERN_ERR "efivars: unable to create new_var sysfs file" + " due to error %d\n", error); + error = sysfs_create_bin_file(&vars_kset->kobj, + &var_subsys_attr_del_var); + if (error) + printk(KERN_ERR "efivars: unable to create del_var sysfs file" + " due to error %d\n", error); /* Don't forget the systab entry */ - - for (i = 0; (attr = efi_subsys_attrs[i]) && !error; i++) { - if (attr->show) - error = subsys_create_file(&efi_subsys, attr); - } - + error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group); if (error) printk(KERN_ERR "efivars: Sysfs attribute export failed with error %d.\n", error); else goto out_free; - subsystem_unregister(&vars_subsys); + kset_unregister(vars_kset); out_firmware_unregister: - firmware_unregister(&efi_subsys); + kobject_put(efi_kobj); out_free: kfree(variable_name); @@ -768,8 +752,8 @@ efivars_exit(void) efivar_unregister(entry); } - subsystem_unregister(&vars_subsys); - firmware_unregister(&efi_subsys); + kset_unregister(vars_kset); + kobject_put(efi_kobj); } module_init(efivars_init); diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c index b767603a07ba38d41c08269e727823c89b910c47..ebfbb2947ae6f18ab604360d79c998db852a4485 100644 --- a/drivers/i2c/chips/isp1301_omap.c +++ b/drivers/i2c/chips/isp1301_omap.c @@ -259,12 +259,6 @@ static inline const char *state_name(struct isp1301 *isp) return state_string(isp->otg.state); } -#ifdef VERBOSE -#define dev_vdbg dev_dbg -#else -#define dev_vdbg(dev, fmt, arg...) do{}while(0) -#endif - /*-------------------------------------------------------------------------*/ /* NOTE: some of this ISP1301 setup is specific to H2 boards; diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 2994523be7bf8ed508160bb3ab60c71467081da1..0cb3d2bb3ab924c8a87c5322ca7dafc3e89f3a08 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -1173,7 +1173,7 @@ static struct kobject *exact_match(dev_t dev, int *part, void *data) { struct gendisk *p = data; *part &= (1 << PARTN_BITS) - 1; - return &p->kobj; + return &p->dev.kobj; } static int exact_lock(dev_t dev, void *data) diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 7b9181b5469d3be9d3e8e0929c5a0c2d4122c8d5..1495792d791734cdfa2763b64eac67d998e13a25 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -4724,10 +4724,8 @@ static void ide_tape_release(struct kref *kref) drive->dsc_overlap = 0; drive->driver_data = NULL; - class_device_destroy(idetape_sysfs_class, - MKDEV(IDETAPE_MAJOR, tape->minor)); - class_device_destroy(idetape_sysfs_class, - MKDEV(IDETAPE_MAJOR, tape->minor + 128)); + device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor)); + device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor + 128)); idetape_devs[tape->minor] = NULL; g->private_data = NULL; put_disk(g); @@ -4884,10 +4882,10 @@ static int ide_tape_probe(ide_drive_t *drive) idetape_setup(drive, tape, minor); - class_device_create(idetape_sysfs_class, NULL, - MKDEV(IDETAPE_MAJOR, minor), &drive->gendev, "%s", tape->name); - class_device_create(idetape_sysfs_class, NULL, - MKDEV(IDETAPE_MAJOR, minor + 128), &drive->gendev, "n%s", tape->name); + device_create(idetape_sysfs_class, &drive->gendev, + MKDEV(IDETAPE_MAJOR, minor), "%s", tape->name); + device_create(idetape_sysfs_class, &drive->gendev, + MKDEV(IDETAPE_MAJOR, minor + 128), "n%s", tape->name); g->fops = &idetape_block_ops; ide_register_region(g); diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 90dc75be3418c91f0baab414181577f62ded696f..511e4321c6b6220916a37b05c81d490bce9f4a47 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -727,33 +727,31 @@ static int nodemgr_bus_match(struct device * dev, struct device_driver * drv) static DEFINE_MUTEX(nodemgr_serialize_remove_uds); +static int __match_ne(struct device *dev, void *data) +{ + struct unit_directory *ud; + struct node_entry *ne = (struct node_entry *)data; + + ud = container_of(dev, struct unit_directory, unit_dev); + return ud->ne == ne; +} + static void nodemgr_remove_uds(struct node_entry *ne) { struct device *dev; - struct unit_directory *tmp, *ud; - - /* Iteration over nodemgr_ud_class.devices has to be protected by - * nodemgr_ud_class.sem, but device_unregister() will eventually - * take nodemgr_ud_class.sem too. Therefore pick out one ud at a time, - * release the semaphore, and then unregister the ud. Since this code - * may be called from other contexts besides the knodemgrds, protect the - * gap after release of the semaphore by nodemgr_serialize_remove_uds. + struct unit_directory *ud; + + /* Use class_find device to iterate the devices. Since this code + * may be called from other contexts besides the knodemgrds, + * protect it by nodemgr_serialize_remove_uds. */ mutex_lock(&nodemgr_serialize_remove_uds); for (;;) { - ud = NULL; - down(&nodemgr_ud_class.sem); - list_for_each_entry(dev, &nodemgr_ud_class.devices, node) { - tmp = container_of(dev, struct unit_directory, - unit_dev); - if (tmp->ne == ne) { - ud = tmp; - break; - } - } - up(&nodemgr_ud_class.sem); - if (ud == NULL) + dev = class_find_device(&nodemgr_ud_class, ne, __match_ne); + if (!dev) break; + ud = container_of(dev, struct unit_directory, unit_dev); + put_device(dev); device_unregister(&ud->unit_dev); device_unregister(&ud->device); } @@ -882,45 +880,66 @@ static struct node_entry *nodemgr_create_node(octlet_t guid, struct csr1212_csr return NULL; } +static int __match_ne_guid(struct device *dev, void *data) +{ + struct node_entry *ne; + u64 *guid = (u64 *)data; + + ne = container_of(dev, struct node_entry, node_dev); + return ne->guid == *guid; +} static struct node_entry *find_entry_by_guid(u64 guid) { struct device *dev; - struct node_entry *ne, *ret_ne = NULL; - - down(&nodemgr_ne_class.sem); - list_for_each_entry(dev, &nodemgr_ne_class.devices, node) { - ne = container_of(dev, struct node_entry, node_dev); + struct node_entry *ne; - if (ne->guid == guid) { - ret_ne = ne; - break; - } - } - up(&nodemgr_ne_class.sem); + dev = class_find_device(&nodemgr_ne_class, &guid, __match_ne_guid); + if (!dev) + return NULL; + ne = container_of(dev, struct node_entry, node_dev); + put_device(dev); - return ret_ne; + return ne; } +struct match_nodeid_param { + struct hpsb_host *host; + nodeid_t nodeid; +}; + +static int __match_ne_nodeid(struct device *dev, void *data) +{ + int found = 0; + struct node_entry *ne; + struct match_nodeid_param *param = (struct match_nodeid_param *)data; + + if (!dev) + goto ret; + ne = container_of(dev, struct node_entry, node_dev); + if (ne->host == param->host && ne->nodeid == param->nodeid) + found = 1; +ret: + return found; +} static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host, nodeid_t nodeid) { struct device *dev; - struct node_entry *ne, *ret_ne = NULL; + struct node_entry *ne; + struct match_nodeid_param param; - down(&nodemgr_ne_class.sem); - list_for_each_entry(dev, &nodemgr_ne_class.devices, node) { - ne = container_of(dev, struct node_entry, node_dev); + param.host = host; + param.nodeid = nodeid; - if (ne->host == host && ne->nodeid == nodeid) { - ret_ne = ne; - break; - } - } - up(&nodemgr_ne_class.sem); + dev = class_find_device(&nodemgr_ne_class, ¶m, __match_ne_nodeid); + if (!dev) + return NULL; + ne = container_of(dev, struct node_entry, node_dev); + put_device(dev); - return ret_ne; + return ne; } @@ -1370,107 +1389,109 @@ static void nodemgr_node_scan(struct host_info *hi, int generation) } } - -static void nodemgr_suspend_ne(struct node_entry *ne) +static int __nodemgr_driver_suspend(struct device *dev, void *data) { - struct device *dev; struct unit_directory *ud; struct device_driver *drv; + struct node_entry *ne = (struct node_entry *)data; int error; - HPSB_DEBUG("Node suspended: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]", - NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid); + ud = container_of(dev, struct unit_directory, unit_dev); + if (ud->ne == ne) { + drv = get_driver(ud->device.driver); + if (drv) { + error = 1; /* release if suspend is not implemented */ + if (drv->suspend) { + down(&ud->device.sem); + error = drv->suspend(&ud->device, PMSG_SUSPEND); + up(&ud->device.sem); + } + if (error) + device_release_driver(&ud->device); + put_driver(drv); + } + } - ne->in_limbo = 1; - WARN_ON(device_create_file(&ne->device, &dev_attr_ne_in_limbo)); + return 0; +} - down(&nodemgr_ud_class.sem); - list_for_each_entry(dev, &nodemgr_ud_class.devices, node) { - ud = container_of(dev, struct unit_directory, unit_dev); - if (ud->ne != ne) - continue; +static int __nodemgr_driver_resume(struct device *dev, void *data) +{ + struct unit_directory *ud; + struct device_driver *drv; + struct node_entry *ne = (struct node_entry *)data; + ud = container_of(dev, struct unit_directory, unit_dev); + if (ud->ne == ne) { drv = get_driver(ud->device.driver); - if (!drv) - continue; - - error = 1; /* release if suspend is not implemented */ - if (drv->suspend) { - down(&ud->device.sem); - error = drv->suspend(&ud->device, PMSG_SUSPEND); - up(&ud->device.sem); + if (drv) { + if (drv->resume) { + down(&ud->device.sem); + drv->resume(&ud->device); + up(&ud->device.sem); + } + put_driver(drv); } - if (error) - device_release_driver(&ud->device); - put_driver(drv); } - up(&nodemgr_ud_class.sem); -} + return 0; +} -static void nodemgr_resume_ne(struct node_entry *ne) +static void nodemgr_suspend_ne(struct node_entry *ne) { - struct device *dev; - struct unit_directory *ud; - struct device_driver *drv; + HPSB_DEBUG("Node suspended: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]", + NODE_BUS_ARGS(ne->host, ne->nodeid), + (unsigned long long)ne->guid); - ne->in_limbo = 0; - device_remove_file(&ne->device, &dev_attr_ne_in_limbo); + ne->in_limbo = 1; + WARN_ON(device_create_file(&ne->device, &dev_attr_ne_in_limbo)); - down(&nodemgr_ud_class.sem); - list_for_each_entry(dev, &nodemgr_ud_class.devices, node) { - ud = container_of(dev, struct unit_directory, unit_dev); - if (ud->ne != ne) - continue; + class_for_each_device(&nodemgr_ud_class, ne, __nodemgr_driver_suspend); +} - drv = get_driver(ud->device.driver); - if (!drv) - continue; - if (drv->resume) { - down(&ud->device.sem); - drv->resume(&ud->device); - up(&ud->device.sem); - } - put_driver(drv); - } - up(&nodemgr_ud_class.sem); +static void nodemgr_resume_ne(struct node_entry *ne) +{ + ne->in_limbo = 0; + device_remove_file(&ne->device, &dev_attr_ne_in_limbo); + class_for_each_device(&nodemgr_ud_class, ne, __nodemgr_driver_resume); HPSB_DEBUG("Node resumed: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]", NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid); } - -static void nodemgr_update_pdrv(struct node_entry *ne) +static int __nodemgr_update_pdrv(struct device *dev, void *data) { - struct device *dev; struct unit_directory *ud; struct device_driver *drv; struct hpsb_protocol_driver *pdrv; + struct node_entry *ne = (struct node_entry *)data; int error; - down(&nodemgr_ud_class.sem); - list_for_each_entry(dev, &nodemgr_ud_class.devices, node) { - ud = container_of(dev, struct unit_directory, unit_dev); - if (ud->ne != ne) - continue; - + ud = container_of(dev, struct unit_directory, unit_dev); + if (ud->ne == ne) { drv = get_driver(ud->device.driver); - if (!drv) - continue; - - error = 0; - pdrv = container_of(drv, struct hpsb_protocol_driver, driver); - if (pdrv->update) { - down(&ud->device.sem); - error = pdrv->update(ud); - up(&ud->device.sem); + if (drv) { + error = 0; + pdrv = container_of(drv, struct hpsb_protocol_driver, + driver); + if (pdrv->update) { + down(&ud->device.sem); + error = pdrv->update(ud); + up(&ud->device.sem); + } + if (error) + device_release_driver(&ud->device); + put_driver(drv); } - if (error) - device_release_driver(&ud->device); - put_driver(drv); } - up(&nodemgr_ud_class.sem); + + return 0; +} + +static void nodemgr_update_pdrv(struct node_entry *ne) +{ + class_for_each_device(&nodemgr_ud_class, ne, __nodemgr_update_pdrv); } @@ -1529,13 +1550,31 @@ static void nodemgr_probe_ne(struct host_info *hi, struct node_entry *ne, int ge put_device(dev); } +struct probe_param { + struct host_info *hi; + int generation; +}; + +static int __nodemgr_node_probe(struct device *dev, void *data) +{ + struct probe_param *param = (struct probe_param *)data; + struct node_entry *ne; + + ne = container_of(dev, struct node_entry, node_dev); + if (!ne->needs_probe) + nodemgr_probe_ne(param->hi, ne, param->generation); + if (ne->needs_probe) + nodemgr_probe_ne(param->hi, ne, param->generation); + return 0; +} static void nodemgr_node_probe(struct host_info *hi, int generation) { struct hpsb_host *host = hi->host; - struct device *dev; - struct node_entry *ne; + struct probe_param param; + param.hi = hi; + param.generation = generation; /* Do some processing of the nodes we've probed. This pulls them * into the sysfs layer if needed, and can result in processing of * unit-directories, or just updating the node and it's @@ -1545,19 +1584,7 @@ static void nodemgr_node_probe(struct host_info *hi, int generation) * while probes are time-consuming. (Well, those probes need some * improvement...) */ - down(&nodemgr_ne_class.sem); - list_for_each_entry(dev, &nodemgr_ne_class.devices, node) { - ne = container_of(dev, struct node_entry, node_dev); - if (!ne->needs_probe) - nodemgr_probe_ne(hi, ne, generation); - } - list_for_each_entry(dev, &nodemgr_ne_class.devices, node) { - ne = container_of(dev, struct node_entry, node_dev); - if (ne->needs_probe) - nodemgr_probe_ne(hi, ne, generation); - } - up(&nodemgr_ne_class.sem); - + class_for_each_device(&nodemgr_ne_class, ¶m, __nodemgr_node_probe); /* If we had a bus reset while we were scanning the bus, it is * possible that we did not probe all nodes. In that case, we @@ -1757,6 +1784,22 @@ static int nodemgr_host_thread(void *__hi) return 0; } +struct host_iter_param { + void *data; + int (*cb)(struct hpsb_host *, void *); +}; + +static int __nodemgr_for_each_host(struct device *dev, void *data) +{ + struct hpsb_host *host; + struct host_iter_param *hip = (struct host_iter_param *)data; + int error = 0; + + host = container_of(dev, struct hpsb_host, host_dev); + error = hip->cb(host, hip->data); + + return error; +} /** * nodemgr_for_each_host - call a function for each IEEE 1394 host * @data: an address to supply to the callback @@ -1771,18 +1814,13 @@ static int nodemgr_host_thread(void *__hi) */ int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *)) { - struct device *dev; - struct hpsb_host *host; - int error = 0; - - down(&hpsb_host_class.sem); - list_for_each_entry(dev, &hpsb_host_class.devices, node) { - host = container_of(dev, struct hpsb_host, host_dev); + struct host_iter_param hip; + int error; - if ((error = cb(host, data))) - break; - } - up(&hpsb_host_class.sem); + hip.cb = cb; + hip.data = data; + error = class_for_each_device(&hpsb_host_class, &hip, + __nodemgr_for_each_host); return error; } diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 3d40506813250e6ba429e8e71224a9e077ce032e..c864ef70fdf9633db07e00723aeceb47bd0cba4a 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -508,19 +508,10 @@ static int add_port(struct ib_device *device, int port_num) p->ibdev = device; p->port_num = port_num; - p->kobj.ktype = &port_type; - p->kobj.parent = kobject_get(&device->ports_parent); - if (!p->kobj.parent) { - ret = -EBUSY; - goto err; - } - - ret = kobject_set_name(&p->kobj, "%d", port_num); - if (ret) - goto err_put; - - ret = kobject_register(&p->kobj); + ret = kobject_init_and_add(&p->kobj, &port_type, + kobject_get(device->ports_parent), + "%d", port_num); if (ret) goto err_put; @@ -549,6 +540,7 @@ static int add_port(struct ib_device *device, int port_num) list_add_tail(&p->kobj.entry, &device->port_list); + kobject_uevent(&p->kobj, KOBJ_ADD); return 0; err_free_pkey: @@ -570,9 +562,7 @@ static int add_port(struct ib_device *device, int port_num) sysfs_remove_group(&p->kobj, &pma_group); err_put: - kobject_put(&device->ports_parent); - -err: + kobject_put(device->ports_parent); kfree(p); return ret; } @@ -694,16 +684,9 @@ int ib_device_register_sysfs(struct ib_device *device) goto err_unregister; } - device->ports_parent.parent = kobject_get(&class_dev->kobj); - if (!device->ports_parent.parent) { - ret = -EBUSY; - goto err_unregister; - } - ret = kobject_set_name(&device->ports_parent, "ports"); - if (ret) - goto err_put; - ret = kobject_register(&device->ports_parent); - if (ret) + device->ports_parent = kobject_create_and_add("ports", + kobject_get(&class_dev->kobj)); + if (!device->ports_parent) goto err_put; if (device->node_type == RDMA_NODE_IB_SWITCH) { @@ -731,7 +714,7 @@ int ib_device_register_sysfs(struct ib_device *device) sysfs_remove_group(p, &pma_group); sysfs_remove_group(p, &port->pkey_group); sysfs_remove_group(p, &port->gid_group); - kobject_unregister(p); + kobject_put(p); } } @@ -755,10 +738,10 @@ void ib_device_unregister_sysfs(struct ib_device *device) sysfs_remove_group(p, &pma_group); sysfs_remove_group(p, &port->pkey_group); sysfs_remove_group(p, &port->gid_group); - kobject_unregister(p); + kobject_put(p); } - kobject_unregister(&device->ports_parent); + kobject_put(device->ports_parent); class_device_unregister(&device->class_dev); } diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index 6a56d86a295105549c0a41205601f7b6c1fd8106..c9e32b46387fa3138b992e02f27795c45fa75750 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -590,6 +590,11 @@ static struct attribute_group ehca_drv_attr_grp = { .attrs = ehca_drv_attrs }; +static struct attribute_group *ehca_drv_attr_groups[] = { + &ehca_drv_attr_grp, + NULL, +}; + #define EHCA_RESOURCE_ATTR(name) \ static ssize_t ehca_show_##name(struct device *dev, \ struct device_attribute *attr, \ @@ -899,6 +904,9 @@ static struct of_platform_driver ehca_driver = { .match_table = ehca_device_table, .probe = ehca_probe, .remove = ehca_remove, + .driver = { + .groups = ehca_drv_attr_groups, + }, }; void ehca_poll_eqs(unsigned long data) @@ -957,10 +965,6 @@ int __init ehca_module_init(void) goto module_init2; } - ret = sysfs_create_group(&ehca_driver.driver.kobj, &ehca_drv_attr_grp); - if (ret) /* only complain; we can live without attributes */ - ehca_gen_err("Cannot create driver attributes ret=%d", ret); - if (ehca_poll_all_eqs != 1) { ehca_gen_err("WARNING!!!"); ehca_gen_err("It is possible to lose interrupts."); @@ -986,7 +990,6 @@ void __exit ehca_module_exit(void) if (ehca_poll_all_eqs == 1) del_timer_sync(&poll_eqs_timer); - sysfs_remove_group(&ehca_driver.driver.kobj, &ehca_drv_attr_grp); ibmebus_unregister_driver(&ehca_driver); ehca_destroy_slab_caches(); diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index 1f152ded1e3c48083840e8119aecea8738be1cd3..fc355981bbab10213855eb4208def7179406bf3d 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c @@ -121,6 +121,9 @@ static struct pci_driver ipath_driver = { .probe = ipath_init_one, .remove = __devexit_p(ipath_remove_one), .id_table = ipath_pci_tbl, + .driver = { + .groups = ipath_driver_attr_groups, + }, }; static void ipath_check_status(struct work_struct *work) @@ -2217,25 +2220,15 @@ static int __init infinipath_init(void) goto bail_unit; } - ret = ipath_driver_create_group(&ipath_driver.driver); - if (ret < 0) { - printk(KERN_ERR IPATH_DRV_NAME ": Unable to create driver " - "sysfs entries: error %d\n", -ret); - goto bail_pci; - } - ret = ipath_init_ipathfs(); if (ret < 0) { printk(KERN_ERR IPATH_DRV_NAME ": Unable to create " "ipathfs: error %d\n", -ret); - goto bail_group; + goto bail_pci; } goto bail; -bail_group: - ipath_driver_remove_group(&ipath_driver.driver); - bail_pci: pci_unregister_driver(&ipath_driver); @@ -2250,8 +2243,6 @@ static void __exit infinipath_cleanup(void) { ipath_exit_ipathfs(); - ipath_driver_remove_group(&ipath_driver.driver); - ipath_cdbg(VERBOSE, "Unregistering pci driver\n"); pci_unregister_driver(&ipath_driver); diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h index 8786dd7922e4e3916170af24d8cb8752793ea7ba..bb1dc075f1d1ee2126fc0e62f7a332637248f00a 100644 --- a/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/drivers/infiniband/hw/ipath/ipath_kernel.h @@ -938,8 +938,7 @@ struct device_driver; extern const char ib_ipath_version[]; -int ipath_driver_create_group(struct device_driver *); -void ipath_driver_remove_group(struct device_driver *); +extern struct attribute_group *ipath_driver_attr_groups[]; int ipath_device_create_group(struct device *, struct ipath_devdata *); void ipath_device_remove_group(struct device *, struct ipath_devdata *); diff --git a/drivers/infiniband/hw/ipath/ipath_sysfs.c b/drivers/infiniband/hw/ipath/ipath_sysfs.c index e1ad7cfc21fd66b89e5f46055fb611b730aa94ab..aa27ca9f03b12b0110677b46141352d043423837 100644 --- a/drivers/infiniband/hw/ipath/ipath_sysfs.c +++ b/drivers/infiniband/hw/ipath/ipath_sysfs.c @@ -683,6 +683,11 @@ static struct attribute_group driver_attr_group = { .attrs = driver_attributes }; +struct attribute_group *ipath_driver_attr_groups[] = { + &driver_attr_group, + NULL, +}; + static DEVICE_ATTR(guid, S_IWUSR | S_IRUGO, show_guid, store_guid); static DEVICE_ATTR(lmc, S_IWUSR | S_IRUGO, show_lmc, store_lmc); static DEVICE_ATTR(lid, S_IWUSR | S_IRUGO, show_lid, store_lid); @@ -753,24 +758,9 @@ int ipath_expose_reset(struct device *dev) return ret; } -int ipath_driver_create_group(struct device_driver *drv) -{ - int ret; - - ret = sysfs_create_group(&drv->kobj, &driver_attr_group); - - return ret; -} - -void ipath_driver_remove_group(struct device_driver *drv) -{ - sysfs_remove_group(&drv->kobj, &driver_attr_group); -} - int ipath_device_create_group(struct device *dev, struct ipath_devdata *dd) { int ret; - char unit[5]; ret = sysfs_create_group(&dev->kobj, &dev_attr_group); if (ret) @@ -780,11 +770,6 @@ int ipath_device_create_group(struct device *dev, struct ipath_devdata *dd) if (ret) goto bail_attrs; - snprintf(unit, sizeof(unit), "%02d", dd->ipath_unit); - ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj, unit); - if (ret == 0) - goto bail; - sysfs_remove_group(&dev->kobj, &dev_counter_attr_group); bail_attrs: sysfs_remove_group(&dev->kobj, &dev_attr_group); @@ -794,11 +779,6 @@ int ipath_device_create_group(struct device *dev, struct ipath_devdata *dd) void ipath_device_remove_group(struct device *dev, struct ipath_devdata *dd) { - char unit[5]; - - snprintf(unit, sizeof(unit), "%02d", dd->ipath_unit); - sysfs_remove_link(&dev->driver->kobj, unit); - sysfs_remove_group(&dev->kobj, &dev_counter_attr_group); sysfs_remove_group(&dev->kobj, &dev_attr_group); diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index f449daef3eedd4d0ce37200e979f3e6f4affb90d..23ae66c76d47f2698f5daeabdf548bab5c03ddbe 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -1544,11 +1544,11 @@ static int __init capi_init(void) return PTR_ERR(capi_class); } - class_device_create(capi_class, NULL, MKDEV(capi_major, 0), NULL, "capi"); + device_create(capi_class, NULL, MKDEV(capi_major, 0), "capi"); #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE if (capinc_tty_init() < 0) { - class_device_destroy(capi_class, MKDEV(capi_major, 0)); + device_destroy(capi_class, MKDEV(capi_major, 0)); class_destroy(capi_class); unregister_chrdev(capi_major, "capi20"); return -ENOMEM; @@ -1576,7 +1576,7 @@ static void __exit capi_exit(void) { proc_exit(); - class_device_destroy(capi_class, MKDEV(capi_major, 0)); + device_destroy(capi_class, MKDEV(capi_major, 0)); class_destroy(capi_class); unregister_chrdev(capi_major, "capi20"); diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index a0317abaeb111fc9ced966f62c11afbd3491bc35..02bdaf22d7ea10b28cbe779dd6097ce52b318b17 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h @@ -106,12 +106,6 @@ enum debuglevel { activated */ }; -/* missing from linux/device.h ... */ -#ifndef dev_notice -#define dev_notice(dev, format, arg...) \ - dev_printk(KERN_NOTICE , dev , format , ## arg) -#endif - /* Kernel message macros for situations where dev_printk and friends cannot be * used for lack of reliable access to a device structure. * linux/usb.h already contains these but in an obsolete form which clutters diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index 47c10b8f89b3f00a16674fec744e334590f523d7..c0f372f1d761312bc648d9deccd8e74609fbc513 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c @@ -3451,7 +3451,7 @@ static int kvm_resume(struct sys_device *dev) } static struct sysdev_class kvm_sysdev_class = { - set_kset_name("kvm"), + .name = "kvm", .suspend = kvm_suspend, .resume = kvm_resume, }; diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index 5c742a526082484f41dbb1592d982a7d010c725f..b7adde4324e498d6bcea193a9bf88cf9db29d1dc 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -875,5 +875,5 @@ adbdev_init(void) adb_dev_class = class_create(THIS_MODULE, "adb"); if (IS_ERR(adb_dev_class)) return; - class_device_create(adb_dev_class, NULL, MKDEV(ADB_MAJOR, 0), NULL, "adb"); + device_create(adb_dev_class, NULL, MKDEV(ADB_MAJOR, 0), "adb"); } diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 6123c70153d3d7db8504cc5eef67ecdc4a14d3a3..ac420b17e16fdbc90c5d3ed2f1c35425c8bcb20f 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -2796,7 +2796,7 @@ static int pmu_sys_resume(struct sys_device *sysdev) #endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */ static struct sysdev_class pmu_sysclass = { - set_kset_name("pmu"), + .name = "pmu", }; static struct sys_device device_pmu = { diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 88c0fd657825fb88aab0eb07611050b2546c3514..f2d24eb3208c97e79bdf33b9d8c396f855f55566 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1109,7 +1109,7 @@ static void event_callback(void *context) list_splice_init(&md->uevent_list, &uevents); spin_unlock_irqrestore(&md->uevent_lock, flags); - dm_send_uevents(&uevents, &md->disk->kobj); + dm_send_uevents(&uevents, &md->disk->dev.kobj); atomic_inc(&md->event_nr); wake_up(&md->eventq); @@ -1530,7 +1530,7 @@ int dm_resume(struct mapped_device *md) *---------------------------------------------------------------*/ void dm_kobject_uevent(struct mapped_device *md) { - kobject_uevent(&md->disk->kobj, KOBJ_CHANGE); + kobject_uevent(&md->disk->dev.kobj, KOBJ_CHANGE); } uint32_t dm_next_uevent_seq(struct mapped_device *md) diff --git a/drivers/md/md.c b/drivers/md/md.c index cef9ebd5a04652d4c3e9f293448c45425531d775..c28a120b4161ea7324eae5160ed2a4c2fc7e0ab6 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -231,7 +231,7 @@ static void mddev_put(mddev_t *mddev) list_del(&mddev->all_mddevs); spin_unlock(&all_mddevs_lock); blk_cleanup_queue(mddev->queue); - kobject_unregister(&mddev->kobj); + kobject_put(&mddev->kobj); } else spin_unlock(&all_mddevs_lock); } @@ -1383,22 +1383,19 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev) return -EBUSY; } bdevname(rdev->bdev,b); - if (kobject_set_name(&rdev->kobj, "dev-%s", b) < 0) - return -ENOMEM; - while ( (s=strchr(rdev->kobj.k_name, '/')) != NULL) + while ( (s=strchr(b, '/')) != NULL) *s = '!'; - + rdev->mddev = mddev; printk(KERN_INFO "md: bind<%s>\n", b); - rdev->kobj.parent = &mddev->kobj; - if ((err = kobject_add(&rdev->kobj))) + if ((err = kobject_add(&rdev->kobj, &mddev->kobj, "dev-%s", b))) goto fail; if (rdev->bdev->bd_part) - ko = &rdev->bdev->bd_part->kobj; + ko = &rdev->bdev->bd_part->dev.kobj; else - ko = &rdev->bdev->bd_disk->kobj; + ko = &rdev->bdev->bd_disk->dev.kobj; if ((err = sysfs_create_link(&rdev->kobj, ko, "block"))) { kobject_del(&rdev->kobj); goto fail; @@ -2036,9 +2033,7 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi if (err) goto abort_free; - rdev->kobj.parent = NULL; - rdev->kobj.ktype = &rdev_ktype; - kobject_init(&rdev->kobj); + kobject_init(&rdev->kobj, &rdev_ktype); rdev->desc_nr = -1; rdev->saved_raid_disk = -1; @@ -3054,6 +3049,7 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data) int partitioned = (MAJOR(dev) != MD_MAJOR); int shift = partitioned ? MdpMinorShift : 0; int unit = MINOR(dev) >> shift; + int error; if (!mddev) return NULL; @@ -3082,12 +3078,13 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data) add_disk(disk); mddev->gendisk = disk; mutex_unlock(&disks_mutex); - mddev->kobj.parent = &disk->kobj; - kobject_set_name(&mddev->kobj, "%s", "md"); - mddev->kobj.ktype = &md_ktype; - if (kobject_register(&mddev->kobj)) + error = kobject_init_and_add(&mddev->kobj, &md_ktype, &disk->dev.kobj, + "%s", "md"); + if (error) printk(KERN_WARNING "md: cannot register %s/md - name in use\n", disk->disk_name); + else + kobject_uevent(&mddev->kobj, KOBJ_ADD); return NULL; } @@ -3359,7 +3356,7 @@ static int do_md_run(mddev_t * mddev) mddev->changed = 1; md_new_event(mddev); - kobject_uevent(&mddev->gendisk->kobj, KOBJ_CHANGE); + kobject_uevent(&mddev->gendisk->dev.kobj, KOBJ_CHANGE); return 0; } diff --git a/drivers/mfd/ucb1x00-assabet.c b/drivers/mfd/ucb1x00-assabet.c index e325fa71f38ba2ad05ebfdb923f4b4c9b3227e11..b7c8e78138653c33611ed98d8d58973454a7ab27 100644 --- a/drivers/mfd/ucb1x00-assabet.c +++ b/drivers/mfd/ucb1x00-assabet.c @@ -20,7 +20,8 @@ #include "ucb1x00.h" #define UCB1X00_ATTR(name,input)\ -static ssize_t name##_show(struct class_device *dev, char *buf) \ +static ssize_t name##_show(struct device *dev, struct device_attribute *attr, + char *buf) \ { \ struct ucb1x00 *ucb = classdev_to_ucb1x00(dev); \ int val; \ @@ -29,7 +30,7 @@ static ssize_t name##_show(struct class_device *dev, char *buf) \ ucb1x00_adc_disable(ucb); \ return sprintf(buf, "%d\n", val); \ } \ -static CLASS_DEVICE_ATTR(name,0444,name##_show,NULL) +static DEVICE_ATTR(name,0444,name##_show,NULL) UCB1X00_ATTR(vbatt, UCB_ADC_INP_AD1); UCB1X00_ATTR(vcharger, UCB_ADC_INP_AD0); @@ -37,17 +38,17 @@ UCB1X00_ATTR(batt_temp, UCB_ADC_INP_AD2); static int ucb1x00_assabet_add(struct ucb1x00_dev *dev) { - class_device_create_file(&dev->ucb->cdev, &class_device_attr_vbatt); - class_device_create_file(&dev->ucb->cdev, &class_device_attr_vcharger); - class_device_create_file(&dev->ucb->cdev, &class_device_attr_batt_temp); + device_create_file(&dev->ucb->dev, &device_attr_vbatt); + device_create_file(&dev->ucb->dev, &device_attr_vcharger); + device_create_file(&dev->ucb->dev, &device_attr_batt_temp); return 0; } static void ucb1x00_assabet_remove(struct ucb1x00_dev *dev) { - class_device_remove_file(&dev->ucb->cdev, &class_device_attr_batt_temp); - class_device_remove_file(&dev->ucb->cdev, &class_device_attr_vcharger); - class_device_remove_file(&dev->ucb->cdev, &class_device_attr_vbatt); + device_remove_file(&dev->ucb->cdev, &device_attr_batt_temp); + device_remove_file(&dev->ucb->cdev, &device_attr_vcharger); + device_remove_file(&dev->ucb->cdev, &device_attr_vbatt); } static struct ucb1x00_driver ucb1x00_assabet_driver = { diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c index e03f1bcd4f9f2621be307cba72b35b3ac4df75dd..f6b10dda31fdfd3f09bc070446956b1113b61f3f 100644 --- a/drivers/mfd/ucb1x00-core.c +++ b/drivers/mfd/ucb1x00-core.c @@ -458,7 +458,7 @@ static int ucb1x00_detect_irq(struct ucb1x00 *ucb) return probe_irq_off(mask); } -static void ucb1x00_release(struct class_device *dev) +static void ucb1x00_release(struct device *dev) { struct ucb1x00 *ucb = classdev_to_ucb1x00(dev); kfree(ucb); @@ -466,7 +466,7 @@ static void ucb1x00_release(struct class_device *dev) static struct class ucb1x00_class = { .name = "ucb1x00", - .release = ucb1x00_release, + .dev_release = ucb1x00_release, }; static int ucb1x00_probe(struct mcp *mcp) @@ -490,9 +490,9 @@ static int ucb1x00_probe(struct mcp *mcp) goto err_disable; - ucb->cdev.class = &ucb1x00_class; - ucb->cdev.dev = &mcp->attached_device; - strlcpy(ucb->cdev.class_id, "ucb1x00", sizeof(ucb->cdev.class_id)); + ucb->dev.class = &ucb1x00_class; + ucb->dev.parent = &mcp->attached_device; + strlcpy(ucb->dev.bus_id, "ucb1x00", sizeof(ucb->dev.bus_id)); spin_lock_init(&ucb->lock); spin_lock_init(&ucb->io_lock); @@ -517,7 +517,7 @@ static int ucb1x00_probe(struct mcp *mcp) mcp_set_drvdata(mcp, ucb); - ret = class_device_register(&ucb->cdev); + ret = device_register(&ucb->dev); if (ret) goto err_irq; @@ -554,7 +554,7 @@ static void ucb1x00_remove(struct mcp *mcp) mutex_unlock(&ucb1x00_mutex); free_irq(ucb->irq, ucb); - class_device_unregister(&ucb->cdev); + device_unregister(&ucb->dev); } int ucb1x00_register_driver(struct ucb1x00_driver *drv) diff --git a/drivers/mfd/ucb1x00.h b/drivers/mfd/ucb1x00.h index ca8df8072d433ff77b04218dbb81c00f1e0e029d..a8ad8a0ed5dbbf0f763cf2e900ada34e55311daf 100644 --- a/drivers/mfd/ucb1x00.h +++ b/drivers/mfd/ucb1x00.h @@ -120,7 +120,7 @@ struct ucb1x00 { u16 irq_fal_enbl; u16 irq_ris_enbl; struct ucb1x00_irq irq_handler[16]; - struct class_device cdev; + struct device dev; struct list_head node; struct list_head devs; }; @@ -144,7 +144,7 @@ struct ucb1x00_driver { int (*resume)(struct ucb1x00_dev *dev); }; -#define classdev_to_ucb1x00(cd) container_of(cd, struct ucb1x00, cdev) +#define classdev_to_ucb1x00(cd) container_of(cd, struct ucb1x00, dev) int ucb1x00_register_driver(struct ucb1x00_driver *); void ucb1x00_unregister_driver(struct ucb1x00_driver *); diff --git a/drivers/misc/ibmasm/command.c b/drivers/misc/ibmasm/command.c index 6497872df524167e6121d6aca87b8ea2d58281e9..1a0e7978226a6b593e048e31ef00e4e40dd13d41 100644 --- a/drivers/misc/ibmasm/command.c +++ b/drivers/misc/ibmasm/command.c @@ -26,11 +26,6 @@ #include "lowlevel.h" static void exec_next_command(struct service_processor *sp); -static void free_command(struct kobject *kobj); - -static struct kobj_type ibmasm_cmd_kobj_type = { - .release = free_command, -}; static atomic_t command_count = ATOMIC_INIT(0); @@ -53,8 +48,7 @@ struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_s } cmd->buffer_size = buffer_size; - kobject_init(&cmd->kobj); - cmd->kobj.ktype = &ibmasm_cmd_kobj_type; + kref_init(&cmd->kref); cmd->lock = &sp->lock; cmd->status = IBMASM_CMD_PENDING; @@ -67,9 +61,9 @@ struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_s return cmd; } -static void free_command(struct kobject *kobj) +void ibmasm_free_command(struct kref *kref) { - struct command *cmd = to_command(kobj); + struct command *cmd = to_command(kref); list_del(&cmd->queue_node); atomic_dec(&command_count); diff --git a/drivers/misc/ibmasm/ibmasm.h b/drivers/misc/ibmasm/ibmasm.h index de860bc6d3f5eb51ea57e210e98e4446b606640d..4d8a4e248b345aec3a2ce128d425f60add73856a 100644 --- a/drivers/misc/ibmasm/ibmasm.h +++ b/drivers/misc/ibmasm/ibmasm.h @@ -31,6 +31,7 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/interrupt.h> +#include <linux/kref.h> #include <linux/device.h> #include <linux/input.h> @@ -92,24 +93,25 @@ struct command { unsigned char *buffer; size_t buffer_size; int status; - struct kobject kobj; + struct kref kref; spinlock_t *lock; }; -#define to_command(c) container_of(c, struct command, kobj) +#define to_command(c) container_of(c, struct command, kref) +void ibmasm_free_command(struct kref *kref); static inline void command_put(struct command *cmd) { unsigned long flags; spinlock_t *lock = cmd->lock; spin_lock_irqsave(lock, flags); - kobject_put(&cmd->kobj); + kref_put(&cmd->kref, ibmasm_free_command); spin_unlock_irqrestore(lock, flags); } static inline void command_get(struct command *cmd) { - kobject_get(&cmd->kobj); + kref_get(&cmd->kref); } diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index 2d1b3df95c5bfbb138f5d0c509fe33345dc2a7b4..54380da343a530ab4a4513eef7501d9e52b6d487 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c @@ -149,7 +149,7 @@ static void tifm_7xx1_switch_media(struct work_struct *work) socket_change_set = fm->socket_change_set; fm->socket_change_set = 0; - dev_dbg(fm->cdev.dev, "checking media set %x\n", + dev_dbg(fm->dev.parent, "checking media set %x\n", socket_change_set); if (!socket_change_set) { @@ -164,7 +164,7 @@ static void tifm_7xx1_switch_media(struct work_struct *work) if (sock) { printk(KERN_INFO "%s : demand removing card from socket %u:%u\n", - fm->cdev.class_id, fm->id, cnt); + fm->dev.bus_id, fm->id, cnt); fm->sockets[cnt] = NULL; sock_addr = sock->addr; spin_unlock_irqrestore(&fm->lock, flags); diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c index 8f77949f93dd879097604fcc817122bfcef60fbc..97544052e7684dda18611c356ca65eab5d9da839 100644 --- a/drivers/misc/tifm_core.c +++ b/drivers/misc/tifm_core.c @@ -160,16 +160,16 @@ static struct bus_type tifm_bus_type = { .resume = tifm_device_resume }; -static void tifm_free(struct class_device *cdev) +static void tifm_free(struct device *dev) { - struct tifm_adapter *fm = container_of(cdev, struct tifm_adapter, cdev); + struct tifm_adapter *fm = container_of(dev, struct tifm_adapter, dev); kfree(fm); } static struct class tifm_adapter_class = { .name = "tifm_adapter", - .release = tifm_free + .dev_release = tifm_free }; struct tifm_adapter *tifm_alloc_adapter(unsigned int num_sockets, @@ -180,9 +180,9 @@ struct tifm_adapter *tifm_alloc_adapter(unsigned int num_sockets, fm = kzalloc(sizeof(struct tifm_adapter) + sizeof(struct tifm_dev*) * num_sockets, GFP_KERNEL); if (fm) { - fm->cdev.class = &tifm_adapter_class; - fm->cdev.dev = dev; - class_device_initialize(&fm->cdev); + fm->dev.class = &tifm_adapter_class; + fm->dev.parent = dev; + device_initialize(&fm->dev); spin_lock_init(&fm->lock); fm->num_sockets = num_sockets; } @@ -203,8 +203,8 @@ int tifm_add_adapter(struct tifm_adapter *fm) if (rc) return rc; - snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id); - rc = class_device_add(&fm->cdev); + snprintf(fm->dev.bus_id, BUS_ID_SIZE, "tifm%u", fm->id); + rc = device_add(&fm->dev); if (rc) { spin_lock(&tifm_adapter_lock); idr_remove(&tifm_adapter_idr, fm->id); @@ -228,13 +228,13 @@ void tifm_remove_adapter(struct tifm_adapter *fm) spin_lock(&tifm_adapter_lock); idr_remove(&tifm_adapter_idr, fm->id); spin_unlock(&tifm_adapter_lock); - class_device_del(&fm->cdev); + device_del(&fm->dev); } EXPORT_SYMBOL(tifm_remove_adapter); void tifm_free_adapter(struct tifm_adapter *fm) { - class_device_put(&fm->cdev); + put_device(&fm->dev); } EXPORT_SYMBOL(tifm_free_adapter); @@ -261,9 +261,9 @@ struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id, sock->card_event = tifm_dummy_event; sock->data_event = tifm_dummy_event; - sock->dev.parent = fm->cdev.dev; + sock->dev.parent = fm->dev.parent; sock->dev.bus = &tifm_bus_type; - sock->dev.dma_mask = fm->cdev.dev->dma_mask; + sock->dev.dma_mask = fm->dev.parent->dma_mask; sock->dev.release = tifm_free_device; snprintf(sock->dev.bus_id, BUS_ID_SIZE, diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 22ed96c4b7bd75a7bedd4a9936f78f9094a7a95a..a0cee86464cae51646b148939d49b6c61b8725a1 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -27,12 +27,10 @@ static void mtd_notify_add(struct mtd_info* mtd) if (!mtd) return; - class_device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2), - NULL, "mtd%d", mtd->index); + device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2), "mtd%d", mtd->index); - class_device_create(mtd_class, NULL, - MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1), - NULL, "mtd%dro", mtd->index); + device_create(mtd_class, NULL, + MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1), "mtd%dro", mtd->index); } static void mtd_notify_remove(struct mtd_info* mtd) @@ -40,8 +38,8 @@ static void mtd_notify_remove(struct mtd_info* mtd) if (!mtd) return; - class_device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2)); - class_device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1)); + device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2)); + device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1)); } static struct mtd_notifier notifier = { diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 7d7758f3ad8c1afb4d4b767d1e25061728f4fade..57772bebff56336cb50c3bde81c0823d13210787 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1179,13 +1179,15 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ for(i = 0; i<IbmVethNumBufferPools; i++) { struct kobject *kobj = &adapter->rx_buff_pool[i].kobj; + int error; + ibmveth_init_buffer_pool(&adapter->rx_buff_pool[i], i, pool_count[i], pool_size[i], pool_active[i]); - kobj->parent = &dev->dev.kobj; - kobject_set_name(kobj, "pool%d", i); - kobj->ktype = &ktype_veth_pool; - kobject_register(kobj); + error = kobject_init_and_add(kobj, &ktype_veth_pool, + &dev->dev.kobj, "pool%d", i); + if (!error) + kobject_uevent(kobj, KOBJ_ADD); } ibmveth_debug_printk("adapter @ 0x%p\n", adapter); @@ -1234,7 +1236,7 @@ static int __devexit ibmveth_remove(struct vio_dev *dev) int i; for(i = 0; i<IbmVethNumBufferPools; i++) - kobject_unregister(&adapter->rx_buff_pool[i].kobj); + kobject_put(&adapter->rx_buff_pool[i].kobj); unregister_netdev(netdev); diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index 97bd9dc2e52e8a2aa1f42ef764e5119e53dc8aba..419861cbc65ecb23ae1172b6559b402bc0caa8d6 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -815,7 +815,7 @@ static int veth_init_connection(u8 rlp) { struct veth_lpar_connection *cnx; struct veth_msg *msgs; - int i, rc; + int i; if ( (rlp == this_lp) || ! HvLpConfig_doLpsCommunicateOnVirtualLan(this_lp, rlp) ) @@ -844,11 +844,7 @@ static int veth_init_connection(u8 rlp) /* This gets us 1 reference, which is held on behalf of the driver * infrastructure. It's released at module unload. */ - kobject_init(&cnx->kobject); - cnx->kobject.ktype = &veth_lpar_connection_ktype; - rc = kobject_set_name(&cnx->kobject, "cnx%.2d", rlp); - if (rc != 0) - return rc; + kobject_init(&cnx->kobject, &veth_lpar_connection_ktype); msgs = kcalloc(VETH_NUMBUFFERS, sizeof(struct veth_msg), GFP_KERNEL); if (! msgs) { @@ -1087,11 +1083,8 @@ static struct net_device * __init veth_probe_one(int vlan, return NULL; } - kobject_init(&port->kobject); - port->kobject.parent = &dev->dev.kobj; - port->kobject.ktype = &veth_port_ktype; - kobject_set_name(&port->kobject, "veth_port"); - if (0 != kobject_add(&port->kobject)) + kobject_init(&port->kobject, &veth_port_ktype); + if (0 != kobject_add(&port->kobject, &dev->dev.kobj, "veth_port")) veth_error("Failed adding port for %s to sysfs.\n", dev->name); veth_info("%s attached to iSeries vlan %d (LPAR map = 0x%.4X)\n", @@ -1711,9 +1704,9 @@ static int __init veth_module_init(void) continue; kobj = &veth_cnx[i]->kobject; - kobj->parent = &veth_driver.driver.kobj; /* If the add failes, complain but otherwise continue */ - if (0 != kobject_add(kobj)) + if (0 != driver_add_kobj(&veth_driver.driver, kobj, + "cnx%.2d", veth_cnx[i]->remote_lp)) veth_error("cnx %d: Failed adding to sysfs.\n", i); } diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index ff37bf437a99e3b955e373b12b2070c1ba37b62d..1d706eae30526003183555c0f897cc9f2e30fea9 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -395,8 +395,7 @@ static int __init cosa_init(void) goto out_chrdev; } for (i=0; i<nr_cards; i++) { - class_device_create(cosa_class, NULL, MKDEV(cosa_major, i), - NULL, "cosa%d", i); + device_create(cosa_class, NULL, MKDEV(cosa_major, i), "cosa%d", i); } err = 0; goto out; @@ -415,7 +414,7 @@ static void __exit cosa_exit(void) printk(KERN_INFO "Unloading the cosa module\n"); for (i=0; i<nr_cards; i++) - class_device_destroy(cosa_class, MKDEV(cosa_major, i)); + device_destroy(cosa_class, MKDEV(cosa_major, i)); class_destroy(cosa_class); for (cosa=cosa_cards; nr_cards--; cosa++) { /* Clean up the per-channel data */ diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c index ebb09e98d215186201293db11260cc022b2d67c6..de34aa9d3136055566204767cd2f5b9cbb28bfb6 100644 --- a/drivers/parisc/pdc_stable.c +++ b/drivers/parisc/pdc_stable.c @@ -120,7 +120,7 @@ struct pdcspath_entry pdcspath_entry_##_name = { \ }; #define PDCS_ATTR(_name, _mode, _show, _store) \ -struct subsys_attribute pdcs_attr_##_name = { \ +struct kobj_attribute pdcs_attr_##_name = { \ .attr = {.name = __stringify(_name), .mode = _mode}, \ .show = _show, \ .store = _store, \ @@ -523,15 +523,15 @@ static struct pdcspath_entry *pdcspath_entries[] = { /** * pdcs_size_read - Stable Storage size output. - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The output buffer to write to. */ -static ssize_t -pdcs_size_read(struct kset *kset, char *buf) +static ssize_t pdcs_size_read(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) { char *out = buf; - if (!kset || !buf) + if (!buf) return -EINVAL; /* show the size of the stable storage */ @@ -542,17 +542,17 @@ pdcs_size_read(struct kset *kset, char *buf) /** * pdcs_auto_read - Stable Storage autoboot/search flag output. - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The output buffer to write to. * @knob: The PF_AUTOBOOT or PF_AUTOSEARCH flag */ -static ssize_t -pdcs_auto_read(struct kset *kset, char *buf, int knob) +static ssize_t pdcs_auto_read(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf, int knob) { char *out = buf; struct pdcspath_entry *pathentry; - if (!kset || !buf) + if (!buf) return -EINVAL; /* Current flags are stored in primary boot path entry */ @@ -568,40 +568,37 @@ pdcs_auto_read(struct kset *kset, char *buf, int knob) /** * pdcs_autoboot_read - Stable Storage autoboot flag output. - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The output buffer to write to. */ -static inline ssize_t -pdcs_autoboot_read(struct kset *kset, char *buf) +static ssize_t pdcs_autoboot_read(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { - return pdcs_auto_read(kset, buf, PF_AUTOBOOT); + return pdcs_auto_read(kobj, attr, buf, PF_AUTOBOOT); } /** * pdcs_autosearch_read - Stable Storage autoboot flag output. - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The output buffer to write to. */ -static inline ssize_t -pdcs_autosearch_read(struct kset *kset, char *buf) +static ssize_t pdcs_autosearch_read(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { - return pdcs_auto_read(kset, buf, PF_AUTOSEARCH); + return pdcs_auto_read(kobj, attr, buf, PF_AUTOSEARCH); } /** * pdcs_timer_read - Stable Storage timer count output (in seconds). - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The output buffer to write to. * * The value of the timer field correponds to a number of seconds in powers of 2. */ -static ssize_t -pdcs_timer_read(struct kset *kset, char *buf) +static ssize_t pdcs_timer_read(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { char *out = buf; struct pdcspath_entry *pathentry; - if (!kset || !buf) + if (!buf) return -EINVAL; /* Current flags are stored in primary boot path entry */ @@ -618,15 +615,14 @@ pdcs_timer_read(struct kset *kset, char *buf) /** * pdcs_osid_read - Stable Storage OS ID register output. - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The output buffer to write to. */ -static ssize_t -pdcs_osid_read(struct kset *kset, char *buf) +static ssize_t pdcs_osid_read(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { char *out = buf; - if (!kset || !buf) + if (!buf) return -EINVAL; out += sprintf(out, "%s dependent data (0x%.4x)\n", @@ -637,18 +633,17 @@ pdcs_osid_read(struct kset *kset, char *buf) /** * pdcs_osdep1_read - Stable Storage OS-Dependent data area 1 output. - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The output buffer to write to. * * This can hold 16 bytes of OS-Dependent data. */ -static ssize_t -pdcs_osdep1_read(struct kset *kset, char *buf) +static ssize_t pdcs_osdep1_read(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { char *out = buf; u32 result[4]; - if (!kset || !buf) + if (!buf) return -EINVAL; if (pdc_stable_read(PDCS_ADDR_OSD1, &result, sizeof(result)) != PDC_OK) @@ -664,18 +659,17 @@ pdcs_osdep1_read(struct kset *kset, char *buf) /** * pdcs_diagnostic_read - Stable Storage Diagnostic register output. - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The output buffer to write to. * * I have NFC how to interpret the content of that register ;-). */ -static ssize_t -pdcs_diagnostic_read(struct kset *kset, char *buf) +static ssize_t pdcs_diagnostic_read(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { char *out = buf; u32 result; - if (!kset || !buf) + if (!buf) return -EINVAL; /* get diagnostic */ @@ -689,18 +683,17 @@ pdcs_diagnostic_read(struct kset *kset, char *buf) /** * pdcs_fastsize_read - Stable Storage FastSize register output. - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The output buffer to write to. * * This register holds the amount of system RAM to be tested during boot sequence. */ -static ssize_t -pdcs_fastsize_read(struct kset *kset, char *buf) +static ssize_t pdcs_fastsize_read(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { char *out = buf; u32 result; - if (!kset || !buf) + if (!buf) return -EINVAL; /* get fast-size */ @@ -718,13 +711,12 @@ pdcs_fastsize_read(struct kset *kset, char *buf) /** * pdcs_osdep2_read - Stable Storage OS-Dependent data area 2 output. - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The output buffer to write to. * * This can hold pdcs_size - 224 bytes of OS-Dependent data, when available. */ -static ssize_t -pdcs_osdep2_read(struct kset *kset, char *buf) +static ssize_t pdcs_osdep2_read(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { char *out = buf; unsigned long size; @@ -736,7 +728,7 @@ pdcs_osdep2_read(struct kset *kset, char *buf) size = pdcs_size - 224; - if (!kset || !buf) + if (!buf) return -EINVAL; for (i=0; i<size; i+=4) { @@ -751,7 +743,6 @@ pdcs_osdep2_read(struct kset *kset, char *buf) /** * pdcs_auto_write - This function handles autoboot/search flag modifying. - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The input buffer to read from. * @count: The number of bytes to be read. * @knob: The PF_AUTOBOOT or PF_AUTOSEARCH flag @@ -760,8 +751,9 @@ pdcs_osdep2_read(struct kset *kset, char *buf) * We expect a precise syntax: * \"n\" (n == 0 or 1) to toggle AutoBoot Off or On */ -static ssize_t -pdcs_auto_write(struct kset *kset, const char *buf, size_t count, int knob) +static ssize_t pdcs_auto_write(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, + size_t count, int knob) { struct pdcspath_entry *pathentry; unsigned char flags; @@ -771,7 +763,7 @@ pdcs_auto_write(struct kset *kset, const char *buf, size_t count, int knob) if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if (!kset || !buf || !count) + if (!buf || !count) return -EINVAL; /* We'll use a local copy of buf */ @@ -826,7 +818,6 @@ pdcs_auto_write(struct kset *kset, const char *buf, size_t count, int knob) /** * pdcs_autoboot_write - This function handles autoboot flag modifying. - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The input buffer to read from. * @count: The number of bytes to be read. * @@ -834,15 +825,15 @@ pdcs_auto_write(struct kset *kset, const char *buf, size_t count, int knob) * We expect a precise syntax: * \"n\" (n == 0 or 1) to toggle AutoSearch Off or On */ -static inline ssize_t -pdcs_autoboot_write(struct kset *kset, const char *buf, size_t count) +static ssize_t pdcs_autoboot_write(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) { - return pdcs_auto_write(kset, buf, count, PF_AUTOBOOT); + return pdcs_auto_write(kset, attr, buf, count, PF_AUTOBOOT); } /** * pdcs_autosearch_write - This function handles autosearch flag modifying. - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The input buffer to read from. * @count: The number of bytes to be read. * @@ -850,15 +841,15 @@ pdcs_autoboot_write(struct kset *kset, const char *buf, size_t count) * We expect a precise syntax: * \"n\" (n == 0 or 1) to toggle AutoSearch Off or On */ -static inline ssize_t -pdcs_autosearch_write(struct kset *kset, const char *buf, size_t count) +static ssize_t pdcs_autosearch_write(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) { - return pdcs_auto_write(kset, buf, count, PF_AUTOSEARCH); + return pdcs_auto_write(kset, attr, buf, count, PF_AUTOSEARCH); } /** * pdcs_osdep1_write - Stable Storage OS-Dependent data area 1 input. - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The input buffer to read from. * @count: The number of bytes to be read. * @@ -866,15 +857,16 @@ pdcs_autosearch_write(struct kset *kset, const char *buf, size_t count) * write approach. It's up to userspace to deal with it when constructing * its input buffer. */ -static ssize_t -pdcs_osdep1_write(struct kset *kset, const char *buf, size_t count) +static ssize_t pdcs_osdep1_write(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) { u8 in[16]; if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if (!kset || !buf || !count) + if (!buf || !count) return -EINVAL; if (unlikely(pdcs_osid != OS_ID_LINUX)) @@ -895,7 +887,6 @@ pdcs_osdep1_write(struct kset *kset, const char *buf, size_t count) /** * pdcs_osdep2_write - Stable Storage OS-Dependent data area 2 input. - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The input buffer to read from. * @count: The number of bytes to be read. * @@ -903,8 +894,9 @@ pdcs_osdep1_write(struct kset *kset, const char *buf, size_t count) * byte-by-byte write approach. It's up to userspace to deal with it when * constructing its input buffer. */ -static ssize_t -pdcs_osdep2_write(struct kset *kset, const char *buf, size_t count) +static ssize_t pdcs_osdep2_write(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) { unsigned long size; unsigned short i; @@ -913,7 +905,7 @@ pdcs_osdep2_write(struct kset *kset, const char *buf, size_t count) if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if (!kset || !buf || !count) + if (!buf || !count) return -EINVAL; if (unlikely(pdcs_size <= 224)) @@ -951,21 +943,25 @@ static PDCS_ATTR(diagnostic, 0400, pdcs_diagnostic_read, NULL); static PDCS_ATTR(fastsize, 0400, pdcs_fastsize_read, NULL); static PDCS_ATTR(osdep2, 0600, pdcs_osdep2_read, pdcs_osdep2_write); -static struct subsys_attribute *pdcs_subsys_attrs[] = { - &pdcs_attr_size, - &pdcs_attr_autoboot, - &pdcs_attr_autosearch, - &pdcs_attr_timer, - &pdcs_attr_osid, - &pdcs_attr_osdep1, - &pdcs_attr_diagnostic, - &pdcs_attr_fastsize, - &pdcs_attr_osdep2, +static struct attribute *pdcs_subsys_attrs[] = { + &pdcs_attr_size.attr, + &pdcs_attr_autoboot.attr, + &pdcs_attr_autosearch.attr, + &pdcs_attr_timer.attr, + &pdcs_attr_osid.attr, + &pdcs_attr_osdep1.attr, + &pdcs_attr_diagnostic.attr, + &pdcs_attr_fastsize.attr, + &pdcs_attr_osdep2.attr, NULL, }; -static decl_subsys(paths, &ktype_pdcspath, NULL); -static decl_subsys(stable, NULL, NULL); +static struct attribute_group pdcs_attr_group = { + .attrs = pdcs_subsys_attrs, +}; + +static struct kobject *stable_kobj; +static struct kset *paths_kset; /** * pdcs_register_pathentries - Prepares path entries kobjects for sysfs usage. @@ -995,12 +991,12 @@ pdcs_register_pathentries(void) if (err < 0) continue; - if ((err = kobject_set_name(&entry->kobj, "%s", entry->name))) - return err; - kobj_set_kset_s(entry, paths_subsys); - if ((err = kobject_register(&entry->kobj))) + entry->kobj.kset = paths_kset; + err = kobject_init_and_add(&entry->kobj, &ktype_pdcspath, NULL, + "%s", entry->name); + if (err) return err; - + /* kobject is now registered */ write_lock(&entry->rw_lock); entry->ready = 2; @@ -1012,6 +1008,7 @@ pdcs_register_pathentries(void) } write_unlock(&entry->rw_lock); + kobject_uevent(&entry->kobj, KOBJ_ADD); } return 0; @@ -1029,7 +1026,7 @@ pdcs_unregister_pathentries(void) for (i = 0; (entry = pdcspath_entries[i]); i++) { read_lock(&entry->rw_lock); if (entry->ready >= 2) - kobject_unregister(&entry->kobj); + kobject_put(&entry->kobj); read_unlock(&entry->rw_lock); } } @@ -1041,8 +1038,7 @@ pdcs_unregister_pathentries(void) static int __init pdc_stable_init(void) { - struct subsys_attribute *attr; - int i, rc = 0, error = 0; + int rc = 0, error = 0; u32 result; /* find the size of the stable storage */ @@ -1062,21 +1058,24 @@ pdc_stable_init(void) /* the actual result is 16 bits away */ pdcs_osid = (u16)(result >> 16); - /* For now we'll register the stable subsys within this driver */ - if ((rc = firmware_register(&stable_subsys))) + /* For now we'll register the directory at /sys/firmware/stable */ + stable_kobj = kobject_create_and_add("stable", firmware_kobj); + if (!stable_kobj) { + rc = -ENOMEM; goto fail_firmreg; + } /* Don't forget the root entries */ - for (i = 0; (attr = pdcs_subsys_attrs[i]) && !error; i++) - if (attr->show) - error = subsys_create_file(&stable_subsys, attr); - - /* register the paths subsys as a subsystem of stable subsys */ - kobj_set_kset_s(&paths_subsys, stable_subsys); - if ((rc = subsystem_register(&paths_subsys))) - goto fail_subsysreg; + error = sysfs_create_group(stable_kobj, pdcs_attr_group); - /* now we create all "files" for the paths subsys */ + /* register the paths kset as a child of the stable kset */ + paths_kset = kset_create_and_add("paths", NULL, stable_kobj); + if (!paths_kset) { + rc = -ENOMEM; + goto fail_ksetreg; + } + + /* now we create all "files" for the paths kset */ if ((rc = pdcs_register_pathentries())) goto fail_pdcsreg; @@ -1084,10 +1083,10 @@ pdc_stable_init(void) fail_pdcsreg: pdcs_unregister_pathentries(); - subsystem_unregister(&paths_subsys); + kset_unregister(paths_kset); -fail_subsysreg: - firmware_unregister(&stable_subsys); +fail_ksetreg: + kobject_put(stable_kobj); fail_firmreg: printk(KERN_INFO PDCS_PREFIX " bailing out\n"); @@ -1098,9 +1097,8 @@ static void __exit pdc_stable_exit(void) { pdcs_unregister_pathentries(); - subsystem_unregister(&paths_subsys); - - firmware_unregister(&stable_subsys); + kset_unregister(paths_kset); + kobject_put(stable_kobj); } diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c index 47d26b65e99a88265db14a5004a429658b6b287e..750ebd7a4c1047a5144f47ba57e2a115dbdb0c78 100644 --- a/drivers/pci/hotplug/acpiphp_ibm.c +++ b/drivers/pci/hotplug/acpiphp_ibm.c @@ -429,7 +429,7 @@ static int __init ibm_acpiphp_init(void) int retval = 0; acpi_status status; struct acpi_device *device; - struct kobject *sysdir = &pci_hotplug_slots_subsys.kobj; + struct kobject *sysdir = &pci_hotplug_slots_kset->kobj; dbg("%s\n", __FUNCTION__); @@ -476,7 +476,7 @@ static int __init ibm_acpiphp_init(void) static void __exit ibm_acpiphp_exit(void) { acpi_status status; - struct kobject *sysdir = &pci_hotplug_slots_subsys.kobj; + struct kobject *sysdir = &pci_hotplug_slots_kset->kobj; dbg("%s\n", __FUNCTION__); diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index 01c351c176ac27267bc03cdfdcf6c2f0d64e1467..47bb0e1ff3faff303a72cbe17963da8e34f675fc 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -61,7 +61,7 @@ static int debug; static LIST_HEAD(pci_hotplug_slot_list); -struct kset pci_hotplug_slots_subsys; +struct kset *pci_hotplug_slots_kset; static ssize_t hotplug_slot_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) @@ -96,8 +96,6 @@ static struct kobj_type hotplug_slot_ktype = { .release = &hotplug_slot_release, }; -decl_subsys_name(pci_hotplug_slots, slots, &hotplug_slot_ktype, NULL); - /* these strings match up with the values in pci_bus_speed */ static char *pci_bus_speed_strings[] = { "33 MHz PCI", /* 0x00 */ @@ -632,18 +630,19 @@ int pci_hp_register (struct hotplug_slot *slot) return -EINVAL; } - kobject_set_name(&slot->kobj, "%s", slot->name); - kobj_set_kset_s(slot, pci_hotplug_slots_subsys); - /* this can fail if we have already registered a slot with the same name */ - if (kobject_register(&slot->kobj)) { - err("Unable to register kobject"); + slot->kobj.kset = pci_hotplug_slots_kset; + result = kobject_init_and_add(&slot->kobj, &hotplug_slot_ktype, NULL, + "%s", slot->name); + if (result) { + err("Unable to register kobject '%s'", slot->name); return -EINVAL; } - + list_add (&slot->slot_list, &pci_hotplug_slot_list); result = fs_add_slot (slot); + kobject_uevent(&slot->kobj, KOBJ_ADD); dbg ("Added slot %s to the list\n", slot->name); return result; } @@ -672,7 +671,7 @@ int pci_hp_deregister (struct hotplug_slot *slot) fs_remove_slot (slot); dbg ("Removed slot %s from the list\n", slot->name); - kobject_unregister(&slot->kobj); + kobject_put(&slot->kobj); return 0; } @@ -700,11 +699,15 @@ int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot, static int __init pci_hotplug_init (void) { int result; + struct kset *pci_bus_kset; - kobj_set_kset_s(&pci_hotplug_slots_subsys, pci_bus_type.subsys); - result = subsystem_register(&pci_hotplug_slots_subsys); - if (result) { - err("Register subsys with error %d\n", result); + pci_bus_kset = bus_get_kset(&pci_bus_type); + + pci_hotplug_slots_kset = kset_create_and_add("slots", NULL, + &pci_bus_kset->kobj); + if (!pci_hotplug_slots_kset) { + result = -ENOMEM; + err("Register subsys error\n"); goto exit; } result = cpci_hotplug_init(debug); @@ -715,9 +718,9 @@ static int __init pci_hotplug_init (void) info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); goto exit; - + err_subsys: - subsystem_unregister(&pci_hotplug_slots_subsys); + kset_unregister(pci_hotplug_slots_kset); exit: return result; } @@ -725,7 +728,7 @@ static int __init pci_hotplug_init (void) static void __exit pci_hotplug_exit (void) { cpci_hotplug_exit(); - subsystem_unregister(&pci_hotplug_slots_subsys); + kset_unregister(pci_hotplug_slots_kset); } module_init(pci_hotplug_init); @@ -737,7 +740,7 @@ MODULE_LICENSE("GPL"); module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); -EXPORT_SYMBOL_GPL(pci_hotplug_slots_subsys); +EXPORT_SYMBOL_GPL(pci_hotplug_slots_kset); EXPORT_SYMBOL_GPL(pci_hp_register); EXPORT_SYMBOL_GPL(pci_hp_deregister); EXPORT_SYMBOL_GPL(pci_hp_change_slot_info); diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c index a080fedf03327fb0b8fe92a940cc71f68ec25c2e..e32148a8fa125e0d6d7bcf9d017d0db0015d6329 100644 --- a/drivers/pci/hotplug/rpadlpar_sysfs.c +++ b/drivers/pci/hotplug/rpadlpar_sysfs.c @@ -23,44 +23,13 @@ #define MAX_DRC_NAME_LEN 64 -/* Store return code of dlpar operation in attribute struct */ -struct dlpar_io_attr { - int rc; - struct attribute attr; - ssize_t (*store)(struct dlpar_io_attr *dlpar_attr, const char *buf, - size_t nbytes); -}; -/* Common show callback for all attrs, display the return code - * of the dlpar op */ -static ssize_t -dlpar_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) -{ - struct dlpar_io_attr *dlpar_attr = container_of(attr, - struct dlpar_io_attr, attr); - return sprintf(buf, "%d\n", dlpar_attr->rc); -} - -static ssize_t -dlpar_attr_store(struct kobject * kobj, struct attribute * attr, - const char *buf, size_t nbytes) -{ - struct dlpar_io_attr *dlpar_attr = container_of(attr, - struct dlpar_io_attr, attr); - return dlpar_attr->store ? - dlpar_attr->store(dlpar_attr, buf, nbytes) : -EIO; -} - -static struct sysfs_ops dlpar_attr_sysfs_ops = { - .show = dlpar_attr_show, - .store = dlpar_attr_store, -}; - -static ssize_t add_slot_store(struct dlpar_io_attr *dlpar_attr, - const char *buf, size_t nbytes) +static ssize_t add_slot_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t nbytes) { char drc_name[MAX_DRC_NAME_LEN]; char *end; + int rc; if (nbytes >= MAX_DRC_NAME_LEN) return 0; @@ -72,15 +41,25 @@ static ssize_t add_slot_store(struct dlpar_io_attr *dlpar_attr, end = &drc_name[nbytes]; *end = '\0'; - dlpar_attr->rc = dlpar_add_slot(drc_name); + rc = dlpar_add_slot(drc_name); + if (rc) + return rc; return nbytes; } -static ssize_t remove_slot_store(struct dlpar_io_attr *dlpar_attr, - const char *buf, size_t nbytes) +static ssize_t add_slot_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "0\n"); +} + +static ssize_t remove_slot_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t nbytes) { char drc_name[MAX_DRC_NAME_LEN]; + int rc; char *end; if (nbytes >= MAX_DRC_NAME_LEN) @@ -93,22 +72,24 @@ static ssize_t remove_slot_store(struct dlpar_io_attr *dlpar_attr, end = &drc_name[nbytes]; *end = '\0'; - dlpar_attr->rc = dlpar_remove_slot(drc_name); + rc = dlpar_remove_slot(drc_name); + if (rc) + return rc; return nbytes; } -static struct dlpar_io_attr add_slot_attr = { - .rc = 0, - .attr = { .name = ADD_SLOT_ATTR_NAME, .mode = 0644, }, - .store = add_slot_store, -}; +static ssize_t remove_slot_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "0\n"); +} -static struct dlpar_io_attr remove_slot_attr = { - .rc = 0, - .attr = { .name = REMOVE_SLOT_ATTR_NAME, .mode = 0644}, - .store = remove_slot_store, -}; +static struct kobj_attribute add_slot_attr = + __ATTR(ADD_SLOT_ATTR_NAME, 0644, add_slot_show, add_slot_store); + +static struct kobj_attribute remove_slot_attr = + __ATTR(REMOVE_SLOT_ATTR_NAME, 0644, remove_slot_show, remove_slot_store); static struct attribute *default_attrs[] = { &add_slot_attr.attr, @@ -116,37 +97,29 @@ static struct attribute *default_attrs[] = { NULL, }; -static void dlpar_io_release(struct kobject *kobj) -{ - /* noop */ - return; -} - -struct kobj_type ktype_dlpar_io = { - .release = dlpar_io_release, - .sysfs_ops = &dlpar_attr_sysfs_ops, - .default_attrs = default_attrs, +static struct attribute_group dlpar_attr_group = { + .attrs = default_attrs, }; -struct kset dlpar_io_kset = { - .kobj = {.ktype = &ktype_dlpar_io, - .parent = &pci_hotplug_slots_subsys.kobj}, - .ktype = &ktype_dlpar_io, -}; +static struct kobject *dlpar_kobj; int dlpar_sysfs_init(void) { - kobject_set_name(&dlpar_io_kset.kobj, DLPAR_KOBJ_NAME); - if (kset_register(&dlpar_io_kset)) { - printk(KERN_ERR "rpadlpar_io: cannot register kset for %s\n", - kobject_name(&dlpar_io_kset.kobj)); + int error; + + dlpar_kobj = kobject_create_and_add(DLPAR_KOBJ_NAME, + &pci_hotplug_slots_kset->kobj); + if (!dlpar_kobj) return -EINVAL; - } - return 0; + error = sysfs_create_group(dlpar_kobj, &dlpar_attr_group); + if (error) + kobject_put(dlpar_kobj); + return error; } void dlpar_sysfs_exit(void) { - kset_unregister(&dlpar_io_kset); + sysfs_remove_group(dlpar_kobj, &dlpar_attr_group); + kobject_put(dlpar_kobj); } diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 6d1a21611818b92c5cd4524e61d046984cf4c476..c4fa35d1dd7721d7a8288b1bcba6978b6b9412a5 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -1,6 +1,11 @@ /* * drivers/pci/pci-driver.c * + * (C) Copyright 2002-2004, 2007 Greg Kroah-Hartman <greg@kroah.com> + * (C) Copyright 2007 Novell Inc. + * + * Released under the GPL v2 only. + * */ #include <linux/pci.h> @@ -96,17 +101,21 @@ pci_create_newid_file(struct pci_driver *drv) { int error = 0; if (drv->probe != NULL) - error = sysfs_create_file(&drv->driver.kobj, - &driver_attr_new_id.attr); + error = driver_create_file(&drv->driver, &driver_attr_new_id); return error; } +static void pci_remove_newid_file(struct pci_driver *drv) +{ + driver_remove_file(&drv->driver, &driver_attr_new_id); +} #else /* !CONFIG_HOTPLUG */ static inline void pci_free_dynids(struct pci_driver *drv) {} static inline int pci_create_newid_file(struct pci_driver *drv) { return 0; } +static inline void pci_remove_newid_file(struct pci_driver *drv) {} #endif /** @@ -352,50 +361,6 @@ static void pci_device_shutdown(struct device *dev) drv->shutdown(pci_dev); } -#define kobj_to_pci_driver(obj) container_of(obj, struct device_driver, kobj) -#define attr_to_driver_attribute(obj) container_of(obj, struct driver_attribute, attr) - -static ssize_t -pci_driver_attr_show(struct kobject * kobj, struct attribute *attr, char *buf) -{ - struct device_driver *driver = kobj_to_pci_driver(kobj); - struct driver_attribute *dattr = attr_to_driver_attribute(attr); - ssize_t ret; - - if (!get_driver(driver)) - return -ENODEV; - - ret = dattr->show ? dattr->show(driver, buf) : -EIO; - - put_driver(driver); - return ret; -} - -static ssize_t -pci_driver_attr_store(struct kobject * kobj, struct attribute *attr, - const char *buf, size_t count) -{ - struct device_driver *driver = kobj_to_pci_driver(kobj); - struct driver_attribute *dattr = attr_to_driver_attribute(attr); - ssize_t ret; - - if (!get_driver(driver)) - return -ENODEV; - - ret = dattr->store ? dattr->store(driver, buf, count) : -EIO; - - put_driver(driver); - return ret; -} - -static struct sysfs_ops pci_driver_sysfs_ops = { - .show = pci_driver_attr_show, - .store = pci_driver_attr_store, -}; -static struct kobj_type pci_driver_kobj_type = { - .sysfs_ops = &pci_driver_sysfs_ops, -}; - /** * __pci_register_driver - register a new pci driver * @drv: the driver structure to register @@ -417,7 +382,6 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner, drv->driver.bus = &pci_bus_type; drv->driver.owner = owner; drv->driver.mod_name = mod_name; - drv->driver.kobj.ktype = &pci_driver_kobj_type; spin_lock_init(&drv->dynids.lock); INIT_LIST_HEAD(&drv->dynids.list); @@ -447,6 +411,7 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner, void pci_unregister_driver(struct pci_driver *drv) { + pci_remove_newid_file(drv); driver_unregister(&drv->driver); pci_free_dynids(drv); } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index c5ca3134513a6e848461c2546604c293d4ba2e51..5fd585293e7954c777094b6331e5a5fae9c094ca 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1210,16 +1210,19 @@ static void __init pci_sort_breadthfirst_klist(void) struct klist_node *n; struct device *dev; struct pci_dev *pdev; + struct klist *device_klist; - spin_lock(&pci_bus_type.klist_devices.k_lock); - list_for_each_safe(pos, tmp, &pci_bus_type.klist_devices.k_list) { + device_klist = bus_get_device_klist(&pci_bus_type); + + spin_lock(&device_klist->k_lock); + list_for_each_safe(pos, tmp, &device_klist->k_list) { n = container_of(pos, struct klist_node, n_node); dev = container_of(n, struct device, knode_bus); pdev = to_pci_dev(dev); pci_insertion_sort_klist(pdev, &sorted_devices); } - list_splice(&sorted_devices, &pci_bus_type.klist_devices.k_list); - spin_unlock(&pci_bus_type.klist_devices.k_lock); + list_splice(&sorted_devices, &device_klist->k_list); + spin_unlock(&device_klist->k_lock); } static void __init pci_insertion_sort_devices(struct pci_dev *a, struct list_head *list) diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 5cf89a91da1ea275266da0a42d6dada7672e5466..15c18f5246d6d21bbd2c849892ef0f88d536395c 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -312,8 +312,7 @@ pcmcia_create_newid_file(struct pcmcia_driver *drv) { int error = 0; if (drv->probe != NULL) - error = sysfs_create_file(&drv->drv.kobj, - &driver_attr_new_id.attr); + error = driver_create_file(&drv->drv, &driver_attr_new_id); return error; } diff --git a/drivers/power/apm_power.c b/drivers/power/apm_power.c index bbf3ee10da04ad433027963d9831379827cb715f..7e29b90a4f6377d51351828a8bf3daded4ad9d49 100644 --- a/drivers/power/apm_power.c +++ b/drivers/power/apm_power.c @@ -13,6 +13,7 @@ #include <linux/power_supply.h> #include <linux/apm-emulation.h> +static DEFINE_MUTEX(apm_mutex); #define PSY_PROP(psy, prop, val) psy->get_property(psy, \ POWER_SUPPLY_PROP_##prop, val) @@ -23,67 +24,86 @@ static struct power_supply *main_battery; -static void find_main_battery(void) -{ - struct device *dev; - struct power_supply *bat = NULL; - struct power_supply *max_charge_bat = NULL; - struct power_supply *max_energy_bat = NULL; +struct find_bat_param { + struct power_supply *main; + struct power_supply *bat; + struct power_supply *max_charge_bat; + struct power_supply *max_energy_bat; union power_supply_propval full; - int max_charge = 0; - int max_energy = 0; + int max_charge; + int max_energy; +}; - main_battery = NULL; +static int __find_main_battery(struct device *dev, void *data) +{ + struct find_bat_param *bp = (struct find_bat_param *)data; - list_for_each_entry(dev, &power_supply_class->devices, node) { - bat = dev_get_drvdata(dev); + bp->bat = dev_get_drvdata(dev); - if (bat->use_for_apm) { - /* nice, we explicitly asked to report this battery. */ - main_battery = bat; - return; - } + if (bp->bat->use_for_apm) { + /* nice, we explicitly asked to report this battery. */ + bp->main = bp->bat; + return 1; + } - if (!PSY_PROP(bat, CHARGE_FULL_DESIGN, &full) || - !PSY_PROP(bat, CHARGE_FULL, &full)) { - if (full.intval > max_charge) { - max_charge_bat = bat; - max_charge = full.intval; - } - } else if (!PSY_PROP(bat, ENERGY_FULL_DESIGN, &full) || - !PSY_PROP(bat, ENERGY_FULL, &full)) { - if (full.intval > max_energy) { - max_energy_bat = bat; - max_energy = full.intval; - } + if (!PSY_PROP(bp->bat, CHARGE_FULL_DESIGN, &bp->full) || + !PSY_PROP(bp->bat, CHARGE_FULL, &bp->full)) { + if (bp->full.intval > bp->max_charge) { + bp->max_charge_bat = bp->bat; + bp->max_charge = bp->full.intval; + } + } else if (!PSY_PROP(bp->bat, ENERGY_FULL_DESIGN, &bp->full) || + !PSY_PROP(bp->bat, ENERGY_FULL, &bp->full)) { + if (bp->full.intval > bp->max_energy) { + bp->max_energy_bat = bp->bat; + bp->max_energy = bp->full.intval; } } + return 0; +} + +static void find_main_battery(void) +{ + struct find_bat_param bp; + int error; + + memset(&bp, 0, sizeof(struct find_bat_param)); + main_battery = NULL; + bp.main = main_battery; + + error = class_for_each_device(power_supply_class, &bp, + __find_main_battery); + if (error) { + main_battery = bp.main; + return; + } - if ((max_energy_bat && max_charge_bat) && - (max_energy_bat != max_charge_bat)) { + if ((bp.max_energy_bat && bp.max_charge_bat) && + (bp.max_energy_bat != bp.max_charge_bat)) { /* try guess battery with more capacity */ - if (!PSY_PROP(max_charge_bat, VOLTAGE_MAX_DESIGN, &full)) { - if (max_energy > max_charge * full.intval) - main_battery = max_energy_bat; + if (!PSY_PROP(bp.max_charge_bat, VOLTAGE_MAX_DESIGN, + &bp.full)) { + if (bp.max_energy > bp.max_charge * bp.full.intval) + main_battery = bp.max_energy_bat; else - main_battery = max_charge_bat; - } else if (!PSY_PROP(max_energy_bat, VOLTAGE_MAX_DESIGN, - &full)) { - if (max_charge > max_energy / full.intval) - main_battery = max_charge_bat; + main_battery = bp.max_charge_bat; + } else if (!PSY_PROP(bp.max_energy_bat, VOLTAGE_MAX_DESIGN, + &bp.full)) { + if (bp.max_charge > bp.max_energy / bp.full.intval) + main_battery = bp.max_charge_bat; else - main_battery = max_energy_bat; + main_battery = bp.max_energy_bat; } else { /* give up, choice any */ - main_battery = max_energy_bat; + main_battery = bp.max_energy_bat; } - } else if (max_charge_bat) { - main_battery = max_charge_bat; - } else if (max_energy_bat) { - main_battery = max_energy_bat; + } else if (bp.max_charge_bat) { + main_battery = bp.max_charge_bat; + } else if (bp.max_energy_bat) { + main_battery = bp.max_energy_bat; } else { /* give up, try the last if any */ - main_battery = bat; + main_battery = bp.bat; } } @@ -207,10 +227,10 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info) union power_supply_propval status; union power_supply_propval capacity, time_to_full, time_to_empty; - down(&power_supply_class->sem); + mutex_lock(&apm_mutex); find_main_battery(); if (!main_battery) { - up(&power_supply_class->sem); + mutex_unlock(&apm_mutex); return; } @@ -278,7 +298,7 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info) } } - up(&power_supply_class->sem); + mutex_unlock(&apm_mutex); } static int __init apm_battery_init(void) diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index a63b75cf75e22569df77991c9a8fb2329832065b..03d6a38464ef8ca8d27c589b35735b0452d1aa97 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c @@ -20,28 +20,29 @@ struct class *power_supply_class; +static int __power_supply_changed_work(struct device *dev, void *data) +{ + struct power_supply *psy = (struct power_supply *)data; + struct power_supply *pst = dev_get_drvdata(dev); + int i; + + for (i = 0; i < psy->num_supplicants; i++) + if (!strcmp(psy->supplied_to[i], pst->name)) { + if (pst->external_power_changed) + pst->external_power_changed(pst); + } + return 0; +} + static void power_supply_changed_work(struct work_struct *work) { struct power_supply *psy = container_of(work, struct power_supply, changed_work); - int i; dev_dbg(psy->dev, "%s\n", __FUNCTION__); - for (i = 0; i < psy->num_supplicants; i++) { - struct device *dev; - - down(&power_supply_class->sem); - list_for_each_entry(dev, &power_supply_class->devices, node) { - struct power_supply *pst = dev_get_drvdata(dev); - - if (!strcmp(psy->supplied_to[i], pst->name)) { - if (pst->external_power_changed) - pst->external_power_changed(pst); - } - } - up(&power_supply_class->sem); - } + class_for_each_device(power_supply_class, psy, + __power_supply_changed_work); power_supply_update_leds(psy); @@ -55,32 +56,35 @@ void power_supply_changed(struct power_supply *psy) schedule_work(&psy->changed_work); } -int power_supply_am_i_supplied(struct power_supply *psy) +static int __power_supply_am_i_supplied(struct device *dev, void *data) { union power_supply_propval ret = {0,}; - struct device *dev; - - down(&power_supply_class->sem); - list_for_each_entry(dev, &power_supply_class->devices, node) { - struct power_supply *epsy = dev_get_drvdata(dev); - int i; - - for (i = 0; i < epsy->num_supplicants; i++) { - if (!strcmp(epsy->supplied_to[i], psy->name)) { - if (epsy->get_property(epsy, - POWER_SUPPLY_PROP_ONLINE, &ret)) - continue; - if (ret.intval) - goto out; - } + struct power_supply *psy = (struct power_supply *)data; + struct power_supply *epsy = dev_get_drvdata(dev); + int i; + + for (i = 0; i < epsy->num_supplicants; i++) { + if (!strcmp(epsy->supplied_to[i], psy->name)) { + if (epsy->get_property(epsy, + POWER_SUPPLY_PROP_ONLINE, &ret)) + continue; + if (ret.intval) + return ret.intval; } } -out: - up(&power_supply_class->sem); + return 0; +} + +int power_supply_am_i_supplied(struct power_supply *psy) +{ + int error; + + error = class_for_each_device(power_supply_class, psy, + __power_supply_am_i_supplied); - dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, ret.intval); + dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, error); - return ret.intval; + return error; } int power_supply_register(struct device *parent, struct power_supply *psy) diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index f1e00ff54ce880fb94c69a38064abe6680c83933..7e3ad4f3b3432aa89c8a7d9a4d9902453f9adbbf 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -251,20 +251,23 @@ void rtc_update_irq(struct rtc_device *rtc, } EXPORT_SYMBOL_GPL(rtc_update_irq); +static int __rtc_match(struct device *dev, void *data) +{ + char *name = (char *)data; + + if (strncmp(dev->bus_id, name, BUS_ID_SIZE) == 0) + return 1; + return 0; +} + struct rtc_device *rtc_class_open(char *name) { struct device *dev; struct rtc_device *rtc = NULL; - down(&rtc_class->sem); - list_for_each_entry(dev, &rtc_class->devices, node) { - if (strncmp(dev->bus_id, name, BUS_ID_SIZE) == 0) { - dev = get_device(dev); - if (dev) - rtc = to_rtc_device(dev); - break; - } - } + dev = class_find_device(rtc_class, name, __rtc_match); + if (dev) + rtc = to_rtc_device(dev); if (rtc) { if (!try_module_get(rtc->owner)) { @@ -272,7 +275,6 @@ struct rtc_device *rtc_class_open(char *name) rtc = NULL; } } - up(&rtc_class->sem); return rtc; } diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index c7ea9381db9f63050b8589ee05faa466d295120e..d6e93f15440ea1721b243b889a9be1006da2f983 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -2089,6 +2089,11 @@ static struct attribute_group netiucv_drv_attr_group = { .attrs = netiucv_drv_attrs, }; +static struct attribute_group *netiucv_drv_attr_groups[] = { + &netiucv_drv_attr_group, + NULL, +}; + static void netiucv_banner(void) { PRINT_INFO("NETIUCV driver initialized\n"); @@ -2113,7 +2118,6 @@ static void __exit netiucv_exit(void) netiucv_unregister_device(dev); } - sysfs_remove_group(&netiucv_driver.kobj, &netiucv_drv_attr_group); driver_unregister(&netiucv_driver); iucv_unregister(&netiucv_handler, 1); iucv_unregister_dbf_views(); @@ -2133,6 +2137,7 @@ static int __init netiucv_init(void) if (rc) goto out_dbf; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); + netiucv_driver.groups = netiucv_drv_attr_groups; rc = driver_register(&netiucv_driver); if (rc) { PRINT_ERR("NETIUCV: failed to register driver.\n"); @@ -2140,18 +2145,9 @@ static int __init netiucv_init(void) goto out_iucv; } - rc = sysfs_create_group(&netiucv_driver.kobj, &netiucv_drv_attr_group); - if (rc) { - PRINT_ERR("NETIUCV: failed to add driver attributes.\n"); - IUCV_DBF_TEXT_(setup, 2, - "ret %d - netiucv_drv_attr_group\n", rc); - goto out_driver; - } netiucv_banner(); return rc; -out_driver: - driver_unregister(&netiucv_driver); out_iucv: iucv_unregister(&netiucv_handler, 1); out_dbf: diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index e01cbf152a81d3622a5d4a607b103ab472e607d0..86c3f6539a7da8b8612c66916941f92401710559 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -52,6 +52,9 @@ static struct ccw_driver zfcp_ccw_driver = { .set_offline = zfcp_ccw_set_offline, .notify = zfcp_ccw_notify, .shutdown = zfcp_ccw_shutdown, + .driver = { + .groups = zfcp_driver_attr_groups, + }, }; MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id); @@ -251,16 +254,7 @@ zfcp_ccw_notify(struct ccw_device *ccw_device, int event) int __init zfcp_ccw_register(void) { - int retval; - - retval = ccw_driver_register(&zfcp_ccw_driver); - if (retval) - goto out; - retval = zfcp_sysfs_driver_create_files(&zfcp_ccw_driver.driver); - if (retval) - ccw_driver_unregister(&zfcp_ccw_driver); - out: - return retval; + return ccw_driver_register(&zfcp_ccw_driver); } /** diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 8534cf09546c3c120a6b23d4a1a8ebd76a6b7894..06b1079b7f3d8e53dbe0961e40a02b20df2cb5ba 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -27,8 +27,7 @@ extern struct zfcp_data zfcp_data; /******************************** SYSFS *************************************/ -extern int zfcp_sysfs_driver_create_files(struct device_driver *); -extern void zfcp_sysfs_driver_remove_files(struct device_driver *); +extern struct attribute_group *zfcp_driver_attr_groups[]; extern int zfcp_sysfs_adapter_create_files(struct device *); extern void zfcp_sysfs_adapter_remove_files(struct device *); extern int zfcp_sysfs_port_create_files(struct device *, u32); diff --git a/drivers/s390/scsi/zfcp_sysfs_driver.c b/drivers/s390/scsi/zfcp_sysfs_driver.c index 005e62f8593b66c021f28d174965f002f27a12a1..651edd58906a021fc71f6f12693998abadfd00a7 100644 --- a/drivers/s390/scsi/zfcp_sysfs_driver.c +++ b/drivers/s390/scsi/zfcp_sysfs_driver.c @@ -98,28 +98,9 @@ static struct attribute_group zfcp_driver_attr_group = { .attrs = zfcp_driver_attrs, }; -/** - * zfcp_sysfs_create_driver_files - create sysfs driver files - * @dev: pointer to belonging device - * - * Create all sysfs attributes of the zfcp device driver - */ -int -zfcp_sysfs_driver_create_files(struct device_driver *drv) -{ - return sysfs_create_group(&drv->kobj, &zfcp_driver_attr_group); -} - -/** - * zfcp_sysfs_remove_driver_files - remove sysfs driver files - * @dev: pointer to belonging device - * - * Remove all sysfs attributes of the zfcp device driver - */ -void -zfcp_sysfs_driver_remove_files(struct device_driver *drv) -{ - sysfs_remove_group(&drv->kobj, &zfcp_driver_attr_group); -} +struct attribute_group *zfcp_driver_attr_groups[] = { + &zfcp_driver_attr_group, + NULL, +}; #undef ZFCP_LOG_AREA diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 24271a871b8c6a03c8cc971d823527374732e52e..6325115e5b3d31b1fd5be8f05b10d5d4bb472a8b 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -429,6 +429,15 @@ void scsi_unregister(struct Scsi_Host *shost) } EXPORT_SYMBOL(scsi_unregister); +static int __scsi_host_match(struct class_device *cdev, void *data) +{ + struct Scsi_Host *p; + unsigned short *hostnum = (unsigned short *)data; + + p = class_to_shost(cdev); + return p->host_no == *hostnum; +} + /** * scsi_host_lookup - get a reference to a Scsi_Host by host no * @@ -439,19 +448,12 @@ EXPORT_SYMBOL(scsi_unregister); **/ struct Scsi_Host *scsi_host_lookup(unsigned short hostnum) { - struct class *class = &shost_class; struct class_device *cdev; - struct Scsi_Host *shost = ERR_PTR(-ENXIO), *p; + struct Scsi_Host *shost = ERR_PTR(-ENXIO); - down(&class->sem); - list_for_each_entry(cdev, &class->children, node) { - p = class_to_shost(cdev); - if (p->host_no == hostnum) { - shost = scsi_host_get(p); - break; - } - } - up(&class->sem); + cdev = class_find_child(&shost_class, &hostnum, __scsi_host_match); + if (cdev) + shost = scsi_host_get(class_to_shost(cdev)); return shost; } diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 7663841eb4cfe7af81a3ae186f332ffcf34531e4..a3fdc57e2673a75d877a98b4d882eb723760ad94 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -464,7 +464,7 @@ int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd) res = sas_phy_reset(phy, 1); if (res) SAS_DPRINTK("Bus reset of %s failed 0x%x\n", - phy->dev.kobj.k_name, + kobject_name(&phy->dev.kobj), res); if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE) return SUCCESS; diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c index 9d3105b64a7a597ba3f634ad4b270dd72d7e4ff9..9c2df5c857cfc85ff46e8378b786a4dd32602bba 100644 --- a/drivers/serial/icom.c +++ b/drivers/serial/icom.c @@ -48,7 +48,7 @@ #include <linux/vmalloc.h> #include <linux/smp.h> #include <linux/spinlock.h> -#include <linux/kobject.h> +#include <linux/kref.h> #include <linux/firmware.h> #include <linux/bitops.h> @@ -65,7 +65,7 @@ #define ICOM_VERSION_STR "1.3.1" #define NR_PORTS 128 #define ICOM_PORT ((struct icom_port *)port) -#define to_icom_adapter(d) container_of(d, struct icom_adapter, kobj) +#define to_icom_adapter(d) container_of(d, struct icom_adapter, kref) static const struct pci_device_id icom_pci_table[] = { { @@ -141,6 +141,7 @@ static inline void trace(struct icom_port *, char *, unsigned long) {}; #else static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {}; #endif +static void icom_kref_release(struct kref *kref); static void free_port_memory(struct icom_port *icom_port) { @@ -1063,11 +1064,11 @@ static int icom_open(struct uart_port *port) { int retval; - kobject_get(&ICOM_PORT->adapter->kobj); + kref_get(&ICOM_PORT->adapter->kref); retval = startup(ICOM_PORT); if (retval) { - kobject_put(&ICOM_PORT->adapter->kobj); + kref_put(&ICOM_PORT->adapter->kref, icom_kref_release); trace(ICOM_PORT, "STARTUP_ERROR", 0); return retval; } @@ -1088,7 +1089,7 @@ static void icom_close(struct uart_port *port) shutdown(ICOM_PORT); - kobject_put(&ICOM_PORT->adapter->kobj); + kref_put(&ICOM_PORT->adapter->kref, icom_kref_release); } static void icom_set_termios(struct uart_port *port, @@ -1485,18 +1486,14 @@ static void icom_remove_adapter(struct icom_adapter *icom_adapter) pci_release_regions(icom_adapter->pci_dev); } -static void icom_kobj_release(struct kobject *kobj) +static void icom_kref_release(struct kref *kref) { struct icom_adapter *icom_adapter; - icom_adapter = to_icom_adapter(kobj); + icom_adapter = to_icom_adapter(kref); icom_remove_adapter(icom_adapter); } -static struct kobj_type icom_kobj_type = { - .release = icom_kobj_release, -}; - static int __devinit icom_probe(struct pci_dev *dev, const struct pci_device_id *ent) { @@ -1592,8 +1589,7 @@ static int __devinit icom_probe(struct pci_dev *dev, } } - kobject_init(&icom_adapter->kobj); - icom_adapter->kobj.ktype = &icom_kobj_type; + kref_init(&icom_adapter->kref); return 0; probe_exit2: @@ -1619,7 +1615,7 @@ static void __devexit icom_remove(struct pci_dev *dev) icom_adapter = list_entry(tmp, struct icom_adapter, icom_adapter_entry); if (icom_adapter->pci_dev == dev) { - kobject_put(&icom_adapter->kobj); + kref_put(&icom_adapter->kref, icom_kref_release); return; } } diff --git a/drivers/serial/icom.h b/drivers/serial/icom.h index e8578d8cd35e8c9b0f428aa4b6467ba01b75e3bf..0274554967453b632be192c2ae180877d865d73b 100644 --- a/drivers/serial/icom.h +++ b/drivers/serial/icom.h @@ -270,7 +270,7 @@ struct icom_adapter { #define V2_ONE_PORT_RVX_ONE_PORT_IMBED_MDM 0x0251 int numb_ports; struct list_head icom_adapter_entry; - struct kobject kobj; + struct kref kref; }; /* prototype */ diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 93e9de46977adc9b7bff784147c40f634fcf910b..682a6a48fec31e989dee472420cd37bc766c4b9f 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -485,6 +485,15 @@ void spi_unregister_master(struct spi_master *master) } EXPORT_SYMBOL_GPL(spi_unregister_master); +static int __spi_master_match(struct device *dev, void *data) +{ + struct spi_master *m; + u16 *bus_num = data; + + m = container_of(dev, struct spi_master, dev); + return m->bus_num == *bus_num; +} + /** * spi_busnum_to_master - look up master associated with bus_num * @bus_num: the master's bus number @@ -499,17 +508,12 @@ struct spi_master *spi_busnum_to_master(u16 bus_num) { struct device *dev; struct spi_master *master = NULL; - struct spi_master *m; - - down(&spi_master_class.sem); - list_for_each_entry(dev, &spi_master_class.children, node) { - m = container_of(dev, struct spi_master, dev); - if (m->bus_num == bus_num) { - master = spi_master_get(m); - break; - } - } - up(&spi_master_class.sem); + + dev = class_find_device(&spi_master_class, &bus_num, + __spi_master_match); + if (dev) + master = container_of(dev, struct spi_master, dev); + /* reference got in class_find_device */ return master; } EXPORT_SYMBOL_GPL(spi_busnum_to_master); diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index 865f32b63b5c0d2d468348f77a1c2c8c07d34879..cc246faa35909116bb61d19541d47059c99ea0fb 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -34,12 +34,12 @@ struct uio_device { wait_queue_head_t wait; int vma_count; struct uio_info *info; - struct kset map_attr_kset; + struct kobject *map_dir; }; static int uio_major; static DEFINE_IDR(uio_idr); -static struct file_operations uio_fops; +static const struct file_operations uio_fops; /* UIO class infrastructure */ static struct uio_class { @@ -51,47 +51,48 @@ static struct uio_class { * attributes */ -static struct attribute attr_addr = { - .name = "addr", - .mode = S_IRUGO, +struct uio_map { + struct kobject kobj; + struct uio_mem *mem; }; +#define to_map(map) container_of(map, struct uio_map, kobj) -static struct attribute attr_size = { - .name = "size", - .mode = S_IRUGO, -}; -static struct attribute* map_attrs[] = { - &attr_addr, &attr_size, NULL -}; - -static ssize_t map_attr_show(struct kobject *kobj, struct attribute *attr, +static ssize_t map_attr_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { - struct uio_mem *mem = container_of(kobj, struct uio_mem, kobj); + struct uio_map *map = to_map(kobj); + struct uio_mem *mem = map->mem; - if (strncmp(attr->name,"addr",4) == 0) + if (strncmp(attr->attr.name, "addr", 4) == 0) return sprintf(buf, "0x%lx\n", mem->addr); - if (strncmp(attr->name,"size",4) == 0) + if (strncmp(attr->attr.name, "size", 4) == 0) return sprintf(buf, "0x%lx\n", mem->size); return -ENODEV; } -static void map_attr_release(struct kobject *kobj) -{ - /* TODO ??? */ -} +static struct kobj_attribute attr_attribute = + __ATTR(addr, S_IRUGO, map_attr_show, NULL); +static struct kobj_attribute size_attribute = + __ATTR(size, S_IRUGO, map_attr_show, NULL); -static struct sysfs_ops map_attr_ops = { - .show = map_attr_show, +static struct attribute *attrs[] = { + &attr_attribute.attr, + &size_attribute.attr, + NULL, /* need to NULL terminate the list of attributes */ }; +static void map_release(struct kobject *kobj) +{ + struct uio_map *map = to_map(kobj); + kfree(map); +} + static struct kobj_type map_attr_type = { - .release = map_attr_release, - .sysfs_ops = &map_attr_ops, - .default_attrs = map_attrs, + .release = map_release, + .default_attrs = attrs, }; static ssize_t show_name(struct device *dev, @@ -148,6 +149,7 @@ static int uio_dev_add_attributes(struct uio_device *idev) int mi; int map_found = 0; struct uio_mem *mem; + struct uio_map *map; ret = sysfs_create_group(&idev->dev->kobj, &uio_attr_grp); if (ret) @@ -159,31 +161,34 @@ static int uio_dev_add_attributes(struct uio_device *idev) break; if (!map_found) { map_found = 1; - kobject_set_name(&idev->map_attr_kset.kobj,"maps"); - idev->map_attr_kset.ktype = &map_attr_type; - idev->map_attr_kset.kobj.parent = &idev->dev->kobj; - ret = kset_register(&idev->map_attr_kset); - if (ret) - goto err_remove_group; + idev->map_dir = kobject_create_and_add("maps", + &idev->dev->kobj); + if (!idev->map_dir) + goto err; } - kobject_init(&mem->kobj); - kobject_set_name(&mem->kobj,"map%d",mi); - mem->kobj.parent = &idev->map_attr_kset.kobj; - mem->kobj.kset = &idev->map_attr_kset; - ret = kobject_add(&mem->kobj); + map = kzalloc(sizeof(*map), GFP_KERNEL); + if (!map) + goto err; + kobject_init(&map->kobj, &map_attr_type); + map->mem = mem; + mem->map = map; + ret = kobject_add(&map->kobj, idev->map_dir, "map%d", mi); + if (ret) + goto err; + ret = kobject_uevent(&map->kobj, KOBJ_ADD); if (ret) - goto err_remove_maps; + goto err; } return 0; -err_remove_maps: +err: for (mi--; mi>=0; mi--) { mem = &idev->info->mem[mi]; - kobject_unregister(&mem->kobj); + map = mem->map; + kobject_put(&map->kobj); } - kset_unregister(&idev->map_attr_kset); /* Needed ? */ -err_remove_group: + kobject_put(idev->map_dir); sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp); err_group: dev_err(idev->dev, "error creating sysfs files (%d)\n", ret); @@ -198,9 +203,9 @@ static void uio_dev_del_attributes(struct uio_device *idev) mem = &idev->info->mem[mi]; if (mem->size == 0) break; - kobject_unregister(&mem->kobj); + kobject_put(&mem->map->kobj); } - kset_unregister(&idev->map_attr_kset); + kobject_put(idev->map_dir); sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp); } @@ -503,7 +508,7 @@ static int uio_mmap(struct file *filep, struct vm_area_struct *vma) } } -static struct file_operations uio_fops = { +static const struct file_operations uio_fops = { .owner = THIS_MODULE, .open = uio_open, .release = uio_release, diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index c51f8e9312e055222f2c473039d7ffb19eb45451..7c3aaa9c5402bf55a0738e0b310943fa81dde777 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -91,8 +91,8 @@ static int usb_create_newid_file(struct usb_driver *usb_drv) goto exit; if (usb_drv->probe != NULL) - error = sysfs_create_file(&usb_drv->drvwrap.driver.kobj, - &driver_attr_new_id.attr); + error = driver_create_file(&usb_drv->drvwrap.driver, + &driver_attr_new_id); exit: return error; } @@ -103,8 +103,8 @@ static void usb_remove_newid_file(struct usb_driver *usb_drv) return; if (usb_drv->probe != NULL) - sysfs_remove_file(&usb_drv->drvwrap.driver.kobj, - &driver_attr_new_id.attr); + driver_remove_file(&usb_drv->drvwrap.driver, + &driver_attr_new_id); } static void usb_free_dynids(struct usb_driver *usb_drv) diff --git a/fs/block_dev.c b/fs/block_dev.c index 993f78c55221c4c4083ac72114afceadfafd12fe..e48a630ae266331f2ca7e482e0b8eeeea9f65d6b 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -738,9 +738,9 @@ EXPORT_SYMBOL(bd_release); static struct kobject *bdev_get_kobj(struct block_device *bdev) { if (bdev->bd_contains != bdev) - return kobject_get(&bdev->bd_part->kobj); + return kobject_get(&bdev->bd_part->dev.kobj); else - return kobject_get(&bdev->bd_disk->kobj); + return kobject_get(&bdev->bd_disk->dev.kobj); } static struct kobject *bdev_get_holder(struct block_device *bdev) @@ -1176,7 +1176,7 @@ static int do_open(struct block_device *bdev, struct file *file, int for_part) ret = -ENXIO; goto out_first; } - kobject_get(&p->kobj); + kobject_get(&p->dev.kobj); bdev->bd_part = p; bd_set_size(bdev, (loff_t) p->nr_sects << 9); } @@ -1299,7 +1299,7 @@ static int __blkdev_put(struct block_device *bdev, int for_part) module_put(owner); if (bdev->bd_contains != bdev) { - kobject_put(&bdev->bd_part->kobj); + kobject_put(&bdev->bd_part->dev.kobj); bdev->bd_part = NULL; } bdev->bd_disk = NULL; diff --git a/fs/char_dev.c b/fs/char_dev.c index c3bfa76765c45c6c516c467663cdb23e6d08907c..2c7a8b5b45989b25d40f8cb6a283d7ffb8940c5a 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c @@ -510,9 +510,8 @@ struct cdev *cdev_alloc(void) { struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL); if (p) { - p->kobj.ktype = &ktype_cdev_dynamic; INIT_LIST_HEAD(&p->list); - kobject_init(&p->kobj); + kobject_init(&p->kobj, &ktype_cdev_dynamic); } return p; } @@ -529,8 +528,7 @@ void cdev_init(struct cdev *cdev, const struct file_operations *fops) { memset(cdev, 0, sizeof *cdev); INIT_LIST_HEAD(&cdev->list); - cdev->kobj.ktype = &ktype_cdev_default; - kobject_init(&cdev->kobj); + kobject_init(&cdev->kobj, &ktype_cdev_default); cdev->ops = fops; } diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c index dcc6aead70f5ebd3b7a1337bc292484ccadbdb23..e3eb3556622b6808c6d15515e18e597a0ddc4f5b 100644 --- a/fs/coda/psdev.c +++ b/fs/coda/psdev.c @@ -362,8 +362,8 @@ static int init_coda_psdev(void) goto out_chrdev; } for (i = 0; i < MAX_CODADEVS; i++) - class_device_create(coda_psdev_class, NULL, - MKDEV(CODA_PSDEV_MAJOR,i), NULL, "cfs%d", i); + device_create(coda_psdev_class, NULL, + MKDEV(CODA_PSDEV_MAJOR,i), "cfs%d", i); coda_sysctl_init(); goto out; @@ -405,7 +405,7 @@ static int __init init_coda(void) return 0; out: for (i = 0; i < MAX_CODADEVS; i++) - class_device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i)); + device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i)); class_destroy(coda_psdev_class); unregister_chrdev(CODA_PSDEV_MAJOR, "coda"); coda_sysctl_clean(); @@ -424,7 +424,7 @@ static void __exit exit_coda(void) printk("coda: failed to unregister filesystem\n"); } for (i = 0; i < MAX_CODADEVS; i++) - class_device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i)); + device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i)); class_destroy(coda_psdev_class); unregister_chrdev(CODA_PSDEV_MAJOR, "coda"); coda_sysctl_clean(); diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c index 3bf0278ea8435cdcb132662bb13fb17a2e78c004..de3b31d0a37d88a44185cb6be1efeefed6bc1cab 100644 --- a/fs/configfs/mount.c +++ b/fs/configfs/mount.c @@ -128,7 +128,7 @@ void configfs_release_fs(void) } -static decl_subsys(config, NULL, NULL); +static struct kobject *config_kobj; static int __init configfs_init(void) { @@ -140,9 +140,8 @@ static int __init configfs_init(void) if (!configfs_dir_cachep) goto out; - kobj_set_kset_s(&config_subsys, kernel_subsys); - err = subsystem_register(&config_subsys); - if (err) { + config_kobj = kobject_create_and_add("config", kernel_kobj); + if (!config_kobj) { kmem_cache_destroy(configfs_dir_cachep); configfs_dir_cachep = NULL; goto out; @@ -151,7 +150,7 @@ static int __init configfs_init(void) err = register_filesystem(&configfs_fs_type); if (err) { printk(KERN_ERR "configfs: Unable to register filesystem!\n"); - subsystem_unregister(&config_subsys); + kobject_put(config_kobj); kmem_cache_destroy(configfs_dir_cachep); configfs_dir_cachep = NULL; goto out; @@ -160,7 +159,7 @@ static int __init configfs_init(void) err = configfs_inode_init(); if (err) { unregister_filesystem(&configfs_fs_type); - subsystem_unregister(&config_subsys); + kobject_put(config_kobj); kmem_cache_destroy(configfs_dir_cachep); configfs_dir_cachep = NULL; } @@ -171,7 +170,7 @@ static int __init configfs_init(void) static void __exit configfs_exit(void) { unregister_filesystem(&configfs_fs_type); - subsystem_unregister(&config_subsys); + kobject_put(config_kobj); kmem_cache_destroy(configfs_dir_cachep); configfs_dir_cachep = NULL; configfs_inode_exit(); diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 6a713b33992f4caedaecb6ba604c47d25e6e6a07..d26e2826ba5b8242ec3a4ad1bcf3b849d64b5a8a 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -426,20 +426,19 @@ struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry, } EXPORT_SYMBOL_GPL(debugfs_rename); -static decl_subsys(debug, NULL, NULL); +static struct kobject *debug_kobj; static int __init debugfs_init(void) { int retval; - kobj_set_kset_s(&debug_subsys, kernel_subsys); - retval = subsystem_register(&debug_subsys); - if (retval) - return retval; + debug_kobj = kobject_create_and_add("debug", kernel_kobj); + if (!debug_kobj) + return -EINVAL; retval = register_filesystem(&debug_fs_type); if (retval) - subsystem_unregister(&debug_subsys); + kobject_put(debug_kobj); return retval; } @@ -447,7 +446,7 @@ static void __exit debugfs_exit(void) { simple_release_fs(&debugfs_mount, &debugfs_mount_count); unregister_filesystem(&debug_fs_type); - subsystem_unregister(&debug_subsys); + kobject_put(debug_kobj); } core_initcall(debugfs_init); diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index 6353a8384520f20190bc5039fc46e6c006ae5d77..5c108c49cb8cd30128d533630cdd3ac72810839d 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -166,26 +166,7 @@ static struct kobj_type dlm_ktype = { .release = lockspace_kobj_release, }; -static struct kset dlm_kset = { - .ktype = &dlm_ktype, -}; - -static int kobject_setup(struct dlm_ls *ls) -{ - char lsname[DLM_LOCKSPACE_LEN]; - int error; - - memset(lsname, 0, DLM_LOCKSPACE_LEN); - snprintf(lsname, DLM_LOCKSPACE_LEN, "%s", ls->ls_name); - - error = kobject_set_name(&ls->ls_kobj, "%s", lsname); - if (error) - return error; - - ls->ls_kobj.kset = &dlm_kset; - ls->ls_kobj.ktype = &dlm_ktype; - return 0; -} +static struct kset *dlm_kset; static int do_uevent(struct dlm_ls *ls, int in) { @@ -220,24 +201,22 @@ static int do_uevent(struct dlm_ls *ls, int in) int dlm_lockspace_init(void) { - int error; - ls_count = 0; mutex_init(&ls_lock); INIT_LIST_HEAD(&lslist); spin_lock_init(&lslist_lock); - kobject_set_name(&dlm_kset.kobj, "dlm"); - kobj_set_kset_s(&dlm_kset, kernel_subsys); - error = kset_register(&dlm_kset); - if (error) - printk("dlm_lockspace_init: cannot register kset %d\n", error); - return error; + dlm_kset = kset_create_and_add("dlm", NULL, kernel_kobj); + if (!dlm_kset) { + printk(KERN_WARNING "%s: can not create kset\n", __FUNCTION__); + return -ENOMEM; + } + return 0; } void dlm_lockspace_exit(void) { - kset_unregister(&dlm_kset); + kset_unregister(dlm_kset); } static int dlm_scand(void *data) @@ -549,13 +528,12 @@ static int new_lockspace(char *name, int namelen, void **lockspace, goto out_delist; } - error = kobject_setup(ls); - if (error) - goto out_stop; - - error = kobject_register(&ls->ls_kobj); + ls->ls_kobj.kset = dlm_kset; + error = kobject_init_and_add(&ls->ls_kobj, &dlm_ktype, NULL, + "%s", ls->ls_name); if (error) goto out_stop; + kobject_uevent(&ls->ls_kobj, KOBJ_ADD); /* let kobject handle freeing of ls if there's an error */ do_unreg = 1; @@ -601,7 +579,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, kfree(ls->ls_rsbtbl); out_lsfree: if (do_unreg) - kobject_unregister(&ls->ls_kobj); + kobject_put(&ls->ls_kobj); else kfree(ls); out: @@ -750,7 +728,7 @@ static int release_lockspace(struct dlm_ls *ls, int force) dlm_clear_members(ls); dlm_clear_members_gone(ls); kfree(ls->ls_node_array); - kobject_unregister(&ls->ls_kobj); + kobject_put(&ls->ls_kobj); /* The ls structure will be freed when the kobject is done with */ mutex_lock(&ls_lock); diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index e5580bcb923a20e7d86e147f9bb9646b42722d15..0249aa4ae181886cd2a26921a465feb5f8d27d41 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -734,127 +734,40 @@ static int ecryptfs_init_kmem_caches(void) return 0; } -struct ecryptfs_obj { - char *name; - struct list_head slot_list; - struct kobject kobj; -}; - -struct ecryptfs_attribute { - struct attribute attr; - ssize_t(*show) (struct ecryptfs_obj *, char *); - ssize_t(*store) (struct ecryptfs_obj *, const char *, size_t); -}; +static struct kobject *ecryptfs_kobj; -static ssize_t -ecryptfs_attr_store(struct kobject *kobj, - struct attribute *attr, const char *buf, size_t len) +static ssize_t version_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buff) { - struct ecryptfs_obj *obj = container_of(kobj, struct ecryptfs_obj, - kobj); - struct ecryptfs_attribute *attribute = - container_of(attr, struct ecryptfs_attribute, attr); - - return (attribute->store ? attribute->store(obj, buf, len) : 0); + return snprintf(buff, PAGE_SIZE, "%d\n", ECRYPTFS_VERSIONING_MASK); } -static ssize_t -ecryptfs_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) -{ - struct ecryptfs_obj *obj = container_of(kobj, struct ecryptfs_obj, - kobj); - struct ecryptfs_attribute *attribute = - container_of(attr, struct ecryptfs_attribute, attr); - - return (attribute->show ? attribute->show(obj, buf) : 0); -} +static struct kobj_attribute version_attr = __ATTR_RO(version); -static struct sysfs_ops ecryptfs_sysfs_ops = { - .show = ecryptfs_attr_show, - .store = ecryptfs_attr_store +static struct attribute *attributes[] = { + &version_attr.attr, + NULL, }; -static struct kobj_type ecryptfs_ktype = { - .sysfs_ops = &ecryptfs_sysfs_ops +static struct attribute_group attr_group = { + .attrs = attributes, }; -static decl_subsys(ecryptfs, &ecryptfs_ktype, NULL); - -static ssize_t version_show(struct ecryptfs_obj *obj, char *buff) -{ - return snprintf(buff, PAGE_SIZE, "%d\n", ECRYPTFS_VERSIONING_MASK); -} - -static struct ecryptfs_attribute sysfs_attr_version = __ATTR_RO(version); - -static struct ecryptfs_version_str_map_elem { - u32 flag; - char *str; -} ecryptfs_version_str_map[] = { - {ECRYPTFS_VERSIONING_PASSPHRASE, "passphrase"}, - {ECRYPTFS_VERSIONING_PUBKEY, "pubkey"}, - {ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH, "plaintext passthrough"}, - {ECRYPTFS_VERSIONING_POLICY, "policy"}, - {ECRYPTFS_VERSIONING_XATTR, "metadata in extended attribute"}, - {ECRYPTFS_VERSIONING_MULTKEY, "multiple keys per file"} -}; - -static ssize_t version_str_show(struct ecryptfs_obj *obj, char *buff) -{ - int i; - int remaining = PAGE_SIZE; - int total_written = 0; - - buff[0] = '\0'; - for (i = 0; i < ARRAY_SIZE(ecryptfs_version_str_map); i++) { - int entry_size; - - if (!(ECRYPTFS_VERSIONING_MASK - & ecryptfs_version_str_map[i].flag)) - continue; - entry_size = strlen(ecryptfs_version_str_map[i].str); - if ((entry_size + 2) > remaining) - goto out; - memcpy(buff, ecryptfs_version_str_map[i].str, entry_size); - buff[entry_size++] = '\n'; - buff[entry_size] = '\0'; - buff += entry_size; - total_written += entry_size; - remaining -= entry_size; - } -out: - return total_written; -} - -static struct ecryptfs_attribute sysfs_attr_version_str = __ATTR_RO(version_str); - static int do_sysfs_registration(void) { int rc; - rc = subsystem_register(&ecryptfs_subsys); - if (rc) { - printk(KERN_ERR - "Unable to register ecryptfs sysfs subsystem\n"); - goto out; - } - rc = sysfs_create_file(&ecryptfs_subsys.kobj, - &sysfs_attr_version.attr); - if (rc) { - printk(KERN_ERR - "Unable to create ecryptfs version attribute\n"); - subsystem_unregister(&ecryptfs_subsys); + ecryptfs_kobj = kobject_create_and_add("ecryptfs", fs_kobj); + if (!ecryptfs_kobj) { + printk(KERN_ERR "Unable to create ecryptfs kset\n"); + rc = -ENOMEM; goto out; } - rc = sysfs_create_file(&ecryptfs_subsys.kobj, - &sysfs_attr_version_str.attr); + rc = sysfs_create_group(ecryptfs_kobj, &attr_group); if (rc) { printk(KERN_ERR - "Unable to create ecryptfs version_str attribute\n"); - sysfs_remove_file(&ecryptfs_subsys.kobj, - &sysfs_attr_version.attr); - subsystem_unregister(&ecryptfs_subsys); - goto out; + "Unable to create ecryptfs version attributes\n"); + kobject_put(ecryptfs_kobj); } out: return rc; @@ -862,11 +775,8 @@ static int do_sysfs_registration(void) static void do_sysfs_unregistration(void) { - sysfs_remove_file(&ecryptfs_subsys.kobj, - &sysfs_attr_version.attr); - sysfs_remove_file(&ecryptfs_subsys.kobj, - &sysfs_attr_version_str.attr); - subsystem_unregister(&ecryptfs_subsys); + sysfs_remove_group(ecryptfs_kobj, &attr_group); + kobject_put(ecryptfs_kobj); } static int __init ecryptfs_init(void) @@ -894,7 +804,6 @@ static int __init ecryptfs_init(void) printk(KERN_ERR "Failed to register filesystem\n"); goto out_free_kmem_caches; } - kobj_set_kset_s(&ecryptfs_subsys, fs_subsys); rc = do_sysfs_registration(); if (rc) { printk(KERN_ERR "sysfs registration failed\n"); diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 84f9f7dfdf5b6bc1162d57ff5bf4f3845e7d743a..e5e80d1a46870dda75135efca29c793860164b15 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -744,9 +744,6 @@ static inline void unregister_fuseblk(void) } #endif -static decl_subsys(fuse, NULL, NULL); -static decl_subsys(connections, NULL, NULL); - static void fuse_inode_init_once(struct kmem_cache *cachep, void *foo) { struct inode * inode = foo; @@ -791,32 +788,37 @@ static void fuse_fs_cleanup(void) kmem_cache_destroy(fuse_inode_cachep); } +static struct kobject *fuse_kobj; +static struct kobject *connections_kobj; + static int fuse_sysfs_init(void) { int err; - kobj_set_kset_s(&fuse_subsys, fs_subsys); - err = subsystem_register(&fuse_subsys); - if (err) + fuse_kobj = kobject_create_and_add("fuse", fs_kobj); + if (!fuse_kobj) { + err = -ENOMEM; goto out_err; + } - kobj_set_kset_s(&connections_subsys, fuse_subsys); - err = subsystem_register(&connections_subsys); - if (err) + connections_kobj = kobject_create_and_add("connections", fuse_kobj); + if (!connections_kobj) { + err = -ENOMEM; goto out_fuse_unregister; + } return 0; out_fuse_unregister: - subsystem_unregister(&fuse_subsys); + kobject_put(fuse_kobj); out_err: return err; } static void fuse_sysfs_cleanup(void) { - subsystem_unregister(&connections_subsys); - subsystem_unregister(&fuse_subsys); + kobject_put(connections_kobj); + kobject_put(fuse_kobj); } static int __init fuse_init(void) diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c index ae9e6a25fe2ba67d390b507e21f678303ed54e59..a87b098397617cdc82a4fc1ebe0eb9edb121a7c0 100644 --- a/fs/gfs2/locking/dlm/sysfs.c +++ b/fs/gfs2/locking/dlm/sysfs.c @@ -189,51 +189,39 @@ static struct kobj_type gdlm_ktype = { .sysfs_ops = &gdlm_attr_ops, }; -static struct kset gdlm_kset = { - .ktype = &gdlm_ktype, -}; +static struct kset *gdlm_kset; int gdlm_kobject_setup(struct gdlm_ls *ls, struct kobject *fskobj) { int error; - error = kobject_set_name(&ls->kobj, "%s", "lock_module"); - if (error) { - log_error("can't set kobj name %d", error); - return error; - } - - ls->kobj.kset = &gdlm_kset; - ls->kobj.ktype = &gdlm_ktype; - ls->kobj.parent = fskobj; - - error = kobject_register(&ls->kobj); + ls->kobj.kset = gdlm_kset; + error = kobject_init_and_add(&ls->kobj, &gdlm_ktype, fskobj, + "lock_module"); if (error) log_error("can't register kobj %d", error); + kobject_uevent(&ls->kobj, KOBJ_ADD); return error; } void gdlm_kobject_release(struct gdlm_ls *ls) { - kobject_unregister(&ls->kobj); + kobject_put(&ls->kobj); } int gdlm_sysfs_init(void) { - int error; - - kobject_set_name(&gdlm_kset.kobj, "lock_dlm"); - kobj_set_kset_s(&gdlm_kset, kernel_subsys); - error = kset_register(&gdlm_kset); - if (error) - printk("lock_dlm: cannot register kset %d\n", error); - - return error; + gdlm_kset = kset_create_and_add("lock_dlm", NULL, kernel_kobj); + if (!gdlm_kset) { + printk(KERN_WARNING "%s: can not create kset\n", __FUNCTION__); + return -ENOMEM; + } + return 0; } void gdlm_sysfs_exit(void) { - kset_unregister(&gdlm_kset); + kset_unregister(gdlm_kset); } diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index 06e0b7768d9743817eef2715ced2cc1d025b0f2d..3a3176b846f360b1916b94a85bfc55cd26b03f28 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -221,9 +221,7 @@ static struct kobj_type gfs2_ktype = { .sysfs_ops = &gfs2_attr_ops, }; -static struct kset gfs2_kset = { - .ktype = &gfs2_ktype, -}; +static struct kset *gfs2_kset; /* * display struct lm_lockstruct fields @@ -495,14 +493,9 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp) { int error; - sdp->sd_kobj.kset = &gfs2_kset; - sdp->sd_kobj.ktype = &gfs2_ktype; - - error = kobject_set_name(&sdp->sd_kobj, "%s", sdp->sd_table_name); - if (error) - goto fail; - - error = kobject_register(&sdp->sd_kobj); + sdp->sd_kobj.kset = gfs2_kset; + error = kobject_init_and_add(&sdp->sd_kobj, &gfs2_ktype, NULL, + "%s", sdp->sd_table_name); if (error) goto fail; @@ -522,6 +515,7 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp) if (error) goto fail_args; + kobject_uevent(&sdp->sd_kobj, KOBJ_ADD); return 0; fail_args: @@ -531,7 +525,7 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp) fail_lockstruct: sysfs_remove_group(&sdp->sd_kobj, &lockstruct_group); fail_reg: - kobject_unregister(&sdp->sd_kobj); + kobject_put(&sdp->sd_kobj); fail: fs_err(sdp, "error %d adding sysfs files", error); return error; @@ -543,21 +537,22 @@ void gfs2_sys_fs_del(struct gfs2_sbd *sdp) sysfs_remove_group(&sdp->sd_kobj, &args_group); sysfs_remove_group(&sdp->sd_kobj, &counters_group); sysfs_remove_group(&sdp->sd_kobj, &lockstruct_group); - kobject_unregister(&sdp->sd_kobj); + kobject_put(&sdp->sd_kobj); } int gfs2_sys_init(void) { gfs2_sys_margs = NULL; spin_lock_init(&gfs2_sys_margs_lock); - kobject_set_name(&gfs2_kset.kobj, "gfs2"); - kobj_set_kset_s(&gfs2_kset, fs_subsys); - return kset_register(&gfs2_kset); + gfs2_kset = kset_create_and_add("gfs2", NULL, fs_kobj); + if (!gfs2_kset) + return -ENOMEM; + return 0; } void gfs2_sys_uninit(void) { kfree(gfs2_sys_margs); - kset_unregister(&gfs2_kset); + kset_unregister(gfs2_kset); } diff --git a/fs/namespace.c b/fs/namespace.c index 06083885b21e85314e3a196d13c7822dcc7c6e9d..61bf376e29e85bfda2456cb929c0a0eeb38af1b3 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -41,8 +41,8 @@ static struct kmem_cache *mnt_cache __read_mostly; static struct rw_semaphore namespace_sem; /* /sys/fs */ -decl_subsys(fs, NULL, NULL); -EXPORT_SYMBOL_GPL(fs_subsys); +struct kobject *fs_kobj; +EXPORT_SYMBOL_GPL(fs_kobj); static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry) { @@ -1861,10 +1861,9 @@ void __init mnt_init(void) if (err) printk(KERN_WARNING "%s: sysfs_init error: %d\n", __FUNCTION__, err); - err = subsystem_register(&fs_subsys); - if (err) - printk(KERN_WARNING "%s: subsystem_register error: %d\n", - __FUNCTION__, err); + fs_kobj = kobject_create_and_add("fs", NULL); + if (!fs_kobj) + printk(KERN_WARNING "%s: kobj create error\n", __FUNCTION__); init_rootfs(); init_mount_tree(); } diff --git a/fs/ocfs2/cluster/masklog.c b/fs/ocfs2/cluster/masklog.c index a4882c8df945ef402694d8b4a392261a0db45dea..23c732f275293bfdd24dad2d03ddbb07c7c4b8e8 100644 --- a/fs/ocfs2/cluster/masklog.c +++ b/fs/ocfs2/cluster/masklog.c @@ -146,7 +146,7 @@ static struct kset mlog_kset = { .kobj = {.ktype = &mlog_ktype}, }; -int mlog_sys_init(struct kset *o2cb_subsys) +int mlog_sys_init(struct kset *o2cb_kset) { int i = 0; @@ -157,7 +157,7 @@ int mlog_sys_init(struct kset *o2cb_subsys) mlog_attr_ptrs[i] = NULL; kobject_set_name(&mlog_kset.kobj, "logmask"); - kobj_set_kset_s(&mlog_kset, *o2cb_subsys); + mlog_kset.kobj.kset = o2cb_kset; return kset_register(&mlog_kset); } diff --git a/fs/ocfs2/cluster/sys.c b/fs/ocfs2/cluster/sys.c index 64f6f378fd097d4dd33a740b82a8df35224cf7e3..a4b07730b2e1d0abb257a126fce7f3911ae1d434 100644 --- a/fs/ocfs2/cluster/sys.c +++ b/fs/ocfs2/cluster/sys.c @@ -28,96 +28,55 @@ #include <linux/module.h> #include <linux/kobject.h> #include <linux/sysfs.h> +#include <linux/fs.h> #include "ocfs2_nodemanager.h" #include "masklog.h" #include "sys.h" -struct o2cb_attribute { - struct attribute attr; - ssize_t (*show)(char *buf); - ssize_t (*store)(const char *buf, size_t count); -}; - -#define O2CB_ATTR(_name, _mode, _show, _store) \ -struct o2cb_attribute o2cb_attr_##_name = __ATTR(_name, _mode, _show, _store) - -#define to_o2cb_attr(_attr) container_of(_attr, struct o2cb_attribute, attr) -static ssize_t o2cb_interface_revision_show(char *buf) +static ssize_t version_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) { return snprintf(buf, PAGE_SIZE, "%u\n", O2NM_API_VERSION); } - -static O2CB_ATTR(interface_revision, S_IFREG | S_IRUGO, o2cb_interface_revision_show, NULL); +static struct kobj_attribute attr_version = + __ATTR(interface_revision, S_IFREG | S_IRUGO, version_show, NULL); static struct attribute *o2cb_attrs[] = { - &o2cb_attr_interface_revision.attr, + &attr_version.attr, NULL, }; -static ssize_t -o2cb_show(struct kobject * kobj, struct attribute * attr, char * buffer); -static ssize_t -o2cb_store(struct kobject * kobj, struct attribute * attr, - const char * buffer, size_t count); -static struct sysfs_ops o2cb_sysfs_ops = { - .show = o2cb_show, - .store = o2cb_store, +static struct attribute_group o2cb_attr_group = { + .attrs = o2cb_attrs, }; -static struct kobj_type o2cb_subsys_type = { - .default_attrs = o2cb_attrs, - .sysfs_ops = &o2cb_sysfs_ops, -}; - -/* gives us o2cb_subsys */ -static decl_subsys(o2cb, NULL, NULL); - -static ssize_t -o2cb_show(struct kobject * kobj, struct attribute * attr, char * buffer) -{ - struct o2cb_attribute *o2cb_attr = to_o2cb_attr(attr); - struct kset *sbs = to_kset(kobj); - - BUG_ON(sbs != &o2cb_subsys); - - if (o2cb_attr->show) - return o2cb_attr->show(buffer); - return -EIO; -} - -static ssize_t -o2cb_store(struct kobject * kobj, struct attribute * attr, - const char * buffer, size_t count) -{ - struct o2cb_attribute *o2cb_attr = to_o2cb_attr(attr); - struct kset *sbs = to_kset(kobj); - - BUG_ON(sbs != &o2cb_subsys); - - if (o2cb_attr->store) - return o2cb_attr->store(buffer, count); - return -EIO; -} +static struct kset *o2cb_kset; void o2cb_sys_shutdown(void) { mlog_sys_shutdown(); - subsystem_unregister(&o2cb_subsys); + kset_unregister(o2cb_kset); } int o2cb_sys_init(void) { int ret; - o2cb_subsys.kobj.ktype = &o2cb_subsys_type; - ret = subsystem_register(&o2cb_subsys); + o2cb_kset = kset_create_and_add("o2cb", NULL, fs_kobj); + if (!o2cb_kset) + return -ENOMEM; + + ret = sysfs_create_group(&o2cb_kset->kobj, &o2cb_attr_group); if (ret) - return ret; + goto error; - ret = mlog_sys_init(&o2cb_subsys); + ret = mlog_sys_init(o2cb_kset); if (ret) - subsystem_unregister(&o2cb_subsys); + goto error; + return 0; +error: + kset_unregister(o2cb_kset); return ret; } diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 722e12e5acc71e9b90051da29f5611b5e3182f9c..739da701ae7b8fec52d10f48392a85509208e286 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -195,96 +195,45 @@ check_partition(struct gendisk *hd, struct block_device *bdev) return ERR_PTR(res); } -/* - * sysfs bindings for partitions - */ - -struct part_attribute { - struct attribute attr; - ssize_t (*show)(struct hd_struct *,char *); - ssize_t (*store)(struct hd_struct *,const char *, size_t); -}; - -static ssize_t -part_attr_show(struct kobject * kobj, struct attribute * attr, char * page) +static ssize_t part_start_show(struct device *dev, + struct device_attribute *attr, char *buf) { - struct hd_struct * p = container_of(kobj,struct hd_struct,kobj); - struct part_attribute * part_attr = container_of(attr,struct part_attribute,attr); - ssize_t ret = 0; - if (part_attr->show) - ret = part_attr->show(p, page); - return ret; -} -static ssize_t -part_attr_store(struct kobject * kobj, struct attribute * attr, - const char *page, size_t count) -{ - struct hd_struct * p = container_of(kobj,struct hd_struct,kobj); - struct part_attribute * part_attr = container_of(attr,struct part_attribute,attr); - ssize_t ret = 0; + struct hd_struct *p = dev_to_part(dev); - if (part_attr->store) - ret = part_attr->store(p, page, count); - return ret; + return sprintf(buf, "%llu\n",(unsigned long long)p->start_sect); } -static struct sysfs_ops part_sysfs_ops = { - .show = part_attr_show, - .store = part_attr_store, -}; - -static ssize_t part_uevent_store(struct hd_struct * p, - const char *page, size_t count) +static ssize_t part_size_show(struct device *dev, + struct device_attribute *attr, char *buf) { - kobject_uevent(&p->kobj, KOBJ_ADD); - return count; + struct hd_struct *p = dev_to_part(dev); + return sprintf(buf, "%llu\n",(unsigned long long)p->nr_sects); } -static ssize_t part_dev_read(struct hd_struct * p, char *page) -{ - struct gendisk *disk = container_of(p->kobj.parent,struct gendisk,kobj); - dev_t dev = MKDEV(disk->major, disk->first_minor + p->partno); - return print_dev_t(page, dev); -} -static ssize_t part_start_read(struct hd_struct * p, char *page) -{ - return sprintf(page, "%llu\n",(unsigned long long)p->start_sect); -} -static ssize_t part_size_read(struct hd_struct * p, char *page) -{ - return sprintf(page, "%llu\n",(unsigned long long)p->nr_sects); -} -static ssize_t part_stat_read(struct hd_struct * p, char *page) + +static ssize_t part_stat_show(struct device *dev, + struct device_attribute *attr, char *buf) { - return sprintf(page, "%8u %8llu %8u %8llu\n", + struct hd_struct *p = dev_to_part(dev); + + return sprintf(buf, "%8u %8llu %8u %8llu\n", p->ios[0], (unsigned long long)p->sectors[0], p->ios[1], (unsigned long long)p->sectors[1]); } -static struct part_attribute part_attr_uevent = { - .attr = {.name = "uevent", .mode = S_IWUSR }, - .store = part_uevent_store -}; -static struct part_attribute part_attr_dev = { - .attr = {.name = "dev", .mode = S_IRUGO }, - .show = part_dev_read -}; -static struct part_attribute part_attr_start = { - .attr = {.name = "start", .mode = S_IRUGO }, - .show = part_start_read -}; -static struct part_attribute part_attr_size = { - .attr = {.name = "size", .mode = S_IRUGO }, - .show = part_size_read -}; -static struct part_attribute part_attr_stat = { - .attr = {.name = "stat", .mode = S_IRUGO }, - .show = part_stat_read -}; #ifdef CONFIG_FAIL_MAKE_REQUEST +static ssize_t part_fail_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct hd_struct *p = dev_to_part(dev); -static ssize_t part_fail_store(struct hd_struct * p, + return sprintf(buf, "%d\n", p->make_it_fail); +} + +static ssize_t part_fail_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { + struct hd_struct *p = dev_to_part(dev); int i; if (count > 0 && sscanf(buf, "%d", &i) > 0) @@ -292,50 +241,53 @@ static ssize_t part_fail_store(struct hd_struct * p, return count; } -static ssize_t part_fail_read(struct hd_struct * p, char *page) -{ - return sprintf(page, "%d\n", p->make_it_fail); -} -static struct part_attribute part_attr_fail = { - .attr = {.name = "make-it-fail", .mode = S_IRUGO | S_IWUSR }, - .store = part_fail_store, - .show = part_fail_read -}; +#endif +static DEVICE_ATTR(start, S_IRUGO, part_start_show, NULL); +static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL); +static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL); +#ifdef CONFIG_FAIL_MAKE_REQUEST +static struct device_attribute dev_attr_fail = + __ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store); #endif -static struct attribute * default_attrs[] = { - &part_attr_uevent.attr, - &part_attr_dev.attr, - &part_attr_start.attr, - &part_attr_size.attr, - &part_attr_stat.attr, +static struct attribute *part_attrs[] = { + &dev_attr_start.attr, + &dev_attr_size.attr, + &dev_attr_stat.attr, #ifdef CONFIG_FAIL_MAKE_REQUEST - &part_attr_fail.attr, + &dev_attr_fail.attr, #endif - NULL, + NULL }; -extern struct kset block_subsys; +static struct attribute_group part_attr_group = { + .attrs = part_attrs, +}; -static void part_release(struct kobject *kobj) +static struct attribute_group *part_attr_groups[] = { + &part_attr_group, + NULL +}; + +static void part_release(struct device *dev) { - struct hd_struct * p = container_of(kobj,struct hd_struct,kobj); + struct hd_struct *p = dev_to_part(dev); kfree(p); } -struct kobj_type ktype_part = { +struct device_type part_type = { + .name = "partition", + .groups = part_attr_groups, .release = part_release, - .default_attrs = default_attrs, - .sysfs_ops = &part_sysfs_ops, }; static inline void partition_sysfs_add_subdir(struct hd_struct *p) { struct kobject *k; - k = kobject_get(&p->kobj); - p->holder_dir = kobject_add_dir(k, "holders"); + k = kobject_get(&p->dev.kobj); + p->holder_dir = kobject_create_and_add("holders", k); kobject_put(k); } @@ -343,15 +295,16 @@ static inline void disk_sysfs_add_subdirs(struct gendisk *disk) { struct kobject *k; - k = kobject_get(&disk->kobj); - disk->holder_dir = kobject_add_dir(k, "holders"); - disk->slave_dir = kobject_add_dir(k, "slaves"); + k = kobject_get(&disk->dev.kobj); + disk->holder_dir = kobject_create_and_add("holders", k); + disk->slave_dir = kobject_create_and_add("slaves", k); kobject_put(k); } void delete_partition(struct gendisk *disk, int part) { struct hd_struct *p = disk->part[part-1]; + if (!p) return; if (!p->nr_sects) @@ -361,113 +314,55 @@ void delete_partition(struct gendisk *disk, int part) p->nr_sects = 0; p->ios[0] = p->ios[1] = 0; p->sectors[0] = p->sectors[1] = 0; - sysfs_remove_link(&p->kobj, "subsystem"); - kobject_unregister(p->holder_dir); - kobject_uevent(&p->kobj, KOBJ_REMOVE); - kobject_del(&p->kobj); - kobject_put(&p->kobj); + kobject_put(p->holder_dir); + device_del(&p->dev); + put_device(&p->dev); } void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len, int flags) { struct hd_struct *p; + int err; p = kzalloc(sizeof(*p), GFP_KERNEL); if (!p) return; - + p->start_sect = start; p->nr_sects = len; p->partno = part; p->policy = disk->policy; - if (isdigit(disk->kobj.k_name[strlen(disk->kobj.k_name)-1])) - kobject_set_name(&p->kobj, "%sp%d", - kobject_name(&disk->kobj), part); + if (isdigit(disk->dev.bus_id[strlen(disk->dev.bus_id)-1])) + snprintf(p->dev.bus_id, BUS_ID_SIZE, + "%sp%d", disk->dev.bus_id, part); else - kobject_set_name(&p->kobj, "%s%d", - kobject_name(&disk->kobj),part); - p->kobj.parent = &disk->kobj; - p->kobj.ktype = &ktype_part; - kobject_init(&p->kobj); - kobject_add(&p->kobj); - if (!disk->part_uevent_suppress) - kobject_uevent(&p->kobj, KOBJ_ADD); - sysfs_create_link(&p->kobj, &block_subsys.kobj, "subsystem"); + snprintf(p->dev.bus_id, BUS_ID_SIZE, + "%s%d", disk->dev.bus_id, part); + + device_initialize(&p->dev); + p->dev.devt = MKDEV(disk->major, disk->first_minor + part); + p->dev.class = &block_class; + p->dev.type = &part_type; + p->dev.parent = &disk->dev; + disk->part[part-1] = p; + + /* delay uevent until 'holders' subdir is created */ + p->dev.uevent_suppress = 1; + device_add(&p->dev); + partition_sysfs_add_subdir(p); + p->dev.uevent_suppress = 0; if (flags & ADDPART_FLAG_WHOLEDISK) { static struct attribute addpartattr = { .name = "whole_disk", .mode = S_IRUSR | S_IRGRP | S_IROTH, }; - - sysfs_create_file(&p->kobj, &addpartattr); + err = sysfs_create_file(&p->dev.kobj, &addpartattr); } - partition_sysfs_add_subdir(p); - disk->part[part-1] = p; -} -static char *make_block_name(struct gendisk *disk) -{ - char *name; - static char *block_str = "block:"; - int size; - char *s; - - size = strlen(block_str) + strlen(disk->disk_name) + 1; - name = kmalloc(size, GFP_KERNEL); - if (!name) - return NULL; - strcpy(name, block_str); - strcat(name, disk->disk_name); - /* ewww... some of these buggers have / in name... */ - s = strchr(name, '/'); - if (s) - *s = '!'; - return name; -} - -static int disk_sysfs_symlinks(struct gendisk *disk) -{ - struct device *target = get_device(disk->driverfs_dev); - int err; - char *disk_name = NULL; - - if (target) { - disk_name = make_block_name(disk); - if (!disk_name) { - err = -ENOMEM; - goto err_out; - } - - err = sysfs_create_link(&disk->kobj, &target->kobj, "device"); - if (err) - goto err_out_disk_name; - - err = sysfs_create_link(&target->kobj, &disk->kobj, disk_name); - if (err) - goto err_out_dev_link; - } - - err = sysfs_create_link(&disk->kobj, &block_subsys.kobj, - "subsystem"); - if (err) - goto err_out_disk_name_lnk; - - kfree(disk_name); - - return 0; - -err_out_disk_name_lnk: - if (target) { - sysfs_remove_link(&target->kobj, disk_name); -err_out_dev_link: - sysfs_remove_link(&disk->kobj, "device"); -err_out_disk_name: - kfree(disk_name); -err_out: - put_device(target); - } - return err; + /* suppress uevent if the disk supresses it */ + if (!disk->dev.uevent_suppress) + kobject_uevent(&p->dev.kobj, KOBJ_ADD); } /* Not exported, helper to add_disk(). */ @@ -479,19 +374,29 @@ void register_disk(struct gendisk *disk) struct hd_struct *p; int err; - kobject_set_name(&disk->kobj, "%s", disk->disk_name); - /* ewww... some of these buggers have / in name... */ - s = strchr(disk->kobj.k_name, '/'); + disk->dev.parent = disk->driverfs_dev; + disk->dev.devt = MKDEV(disk->major, disk->first_minor); + + strlcpy(disk->dev.bus_id, disk->disk_name, KOBJ_NAME_LEN); + /* ewww... some of these buggers have / in the name... */ + s = strchr(disk->dev.bus_id, '/'); if (s) *s = '!'; - if ((err = kobject_add(&disk->kobj))) + + /* delay uevents, until we scanned partition table */ + disk->dev.uevent_suppress = 1; + + if (device_add(&disk->dev)) return; - err = disk_sysfs_symlinks(disk); +#ifndef CONFIG_SYSFS_DEPRECATED + err = sysfs_create_link(block_depr, &disk->dev.kobj, + kobject_name(&disk->dev.kobj)); if (err) { - kobject_del(&disk->kobj); + device_del(&disk->dev); return; } - disk_sysfs_add_subdirs(disk); +#endif + disk_sysfs_add_subdirs(disk); /* No minors to use for partitions */ if (disk->minors == 1) @@ -505,25 +410,23 @@ void register_disk(struct gendisk *disk) if (!bdev) goto exit; - /* scan partition table, but suppress uevents */ bdev->bd_invalidated = 1; - disk->part_uevent_suppress = 1; err = blkdev_get(bdev, FMODE_READ, 0); - disk->part_uevent_suppress = 0; if (err < 0) goto exit; blkdev_put(bdev); exit: - /* announce disk after possible partitions are already created */ - kobject_uevent(&disk->kobj, KOBJ_ADD); + /* announce disk after possible partitions are created */ + disk->dev.uevent_suppress = 0; + kobject_uevent(&disk->dev.kobj, KOBJ_ADD); /* announce possible partitions */ for (i = 1; i < disk->minors; i++) { p = disk->part[i-1]; if (!p || !p->nr_sects) continue; - kobject_uevent(&p->kobj, KOBJ_ADD); + kobject_uevent(&p->dev.kobj, KOBJ_ADD); } } @@ -602,19 +505,11 @@ void del_gendisk(struct gendisk *disk) disk_stat_set_all(disk, 0); disk->stamp = 0; - kobject_uevent(&disk->kobj, KOBJ_REMOVE); - kobject_unregister(disk->holder_dir); - kobject_unregister(disk->slave_dir); - if (disk->driverfs_dev) { - char *disk_name = make_block_name(disk); - sysfs_remove_link(&disk->kobj, "device"); - if (disk_name) { - sysfs_remove_link(&disk->driverfs_dev->kobj, disk_name); - kfree(disk_name); - } - put_device(disk->driverfs_dev); - disk->driverfs_dev = NULL; - } - sysfs_remove_link(&disk->kobj, "subsystem"); - kobject_del(&disk->kobj); + kobject_put(disk->holder_dir); + kobject_put(disk->slave_dir); + disk->driverfs_dev = NULL; +#ifndef CONFIG_SYSFS_DEPRECATED + sysfs_remove_link(block_depr, disk->dev.bus_id); +#endif + device_del(&disk->dev); } diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index f281cc6584b0bca1f14fab02d464e027f31aabe0..4948d9bc405dfbdb23f30dcd5ad47d103f4e5514 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -440,7 +440,7 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) /** * sysfs_remove_one - remove sysfs_dirent from parent * @acxt: addrm context to use - * @sd: sysfs_dirent to be added + * @sd: sysfs_dirent to be removed * * Mark @sd removed and drop nlink of parent inode if @sd is a * directory. @sd is unlinked from the children list. diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 4045bdcc4b331dbf7f4cdd7c6d781f16021ffbf2..8acf82bba44c60c14f46317448c792abd19ceb52 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -20,43 +20,6 @@ #include "sysfs.h" -#define to_sattr(a) container_of(a,struct subsys_attribute, attr) - -/* - * Subsystem file operations. - * These operations allow subsystems to have files that can be - * read/written. - */ -static ssize_t -subsys_attr_show(struct kobject * kobj, struct attribute * attr, char * page) -{ - struct kset *kset = to_kset(kobj); - struct subsys_attribute * sattr = to_sattr(attr); - ssize_t ret = -EIO; - - if (sattr->show) - ret = sattr->show(kset, page); - return ret; -} - -static ssize_t -subsys_attr_store(struct kobject * kobj, struct attribute * attr, - const char * page, size_t count) -{ - struct kset *kset = to_kset(kobj); - struct subsys_attribute * sattr = to_sattr(attr); - ssize_t ret = -EIO; - - if (sattr->store) - ret = sattr->store(kset, page, count); - return ret; -} - -static struct sysfs_ops subsys_sysfs_ops = { - .show = subsys_attr_show, - .store = subsys_attr_store, -}; - /* * There's one sysfs_buffer for each open file and one * sysfs_open_dirent for each sysfs_dirent with one or more open @@ -66,7 +29,7 @@ static struct sysfs_ops subsys_sysfs_ops = { * sysfs_dirent->s_attr.open points to sysfs_open_dirent. s_attr.open * is protected by sysfs_open_dirent_lock. */ -static spinlock_t sysfs_open_dirent_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(sysfs_open_dirent_lock); struct sysfs_open_dirent { atomic_t refcnt; @@ -354,31 +317,23 @@ static int sysfs_open_file(struct inode *inode, struct file *file) { struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; - struct sysfs_buffer * buffer; - struct sysfs_ops * ops = NULL; - int error; + struct sysfs_buffer *buffer; + struct sysfs_ops *ops; + int error = -EACCES; /* need attr_sd for attr and ops, its parent for kobj */ if (!sysfs_get_active_two(attr_sd)) return -ENODEV; - /* if the kobject has no ktype, then we assume that it is a subsystem - * itself, and use ops for it. - */ - if (kobj->kset && kobj->kset->ktype) - ops = kobj->kset->ktype->sysfs_ops; - else if (kobj->ktype) + /* every kobject with an attribute needs a ktype assigned */ + if (kobj->ktype && kobj->ktype->sysfs_ops) ops = kobj->ktype->sysfs_ops; - else - ops = &subsys_sysfs_ops; - - error = -EACCES; - - /* No sysfs operations, either from having no subsystem, - * or the subsystem have no operations. - */ - if (!ops) + else { + printk(KERN_ERR "missing sysfs attribute operations for " + "kobject: %s\n", kobject_name(kobj)); + WARN_ON(1); goto err_out; + } /* File needs write support. * The inode's perms must say it's ok, diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 3eac20c63c419d45cc666a53251be208ebf1296a..5f66c446615176eff46e1864a7343f228bac19e6 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -19,39 +19,6 @@ #include "sysfs.h" -static int object_depth(struct sysfs_dirent *sd) -{ - int depth = 0; - - for (; sd->s_parent; sd = sd->s_parent) - depth++; - - return depth; -} - -static int object_path_length(struct sysfs_dirent * sd) -{ - int length = 1; - - for (; sd->s_parent; sd = sd->s_parent) - length += strlen(sd->s_name) + 1; - - return length; -} - -static void fill_object_path(struct sysfs_dirent *sd, char *buffer, int length) -{ - --length; - for (; sd->s_parent; sd = sd->s_parent) { - int cur = strlen(sd->s_name); - - /* back up enough to print this bus id with '/' */ - length -= cur; - strncpy(buffer + length, sd->s_name, cur); - *(buffer + --length) = '/'; - } -} - /** * sysfs_create_link - create symlink between two objects. * @kobj: object whose directory we're creating the link in. @@ -112,7 +79,6 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char return error; } - /** * sysfs_remove_link - remove symlink in object's directory. * @kobj: object we're acting for. @@ -124,24 +90,54 @@ void sysfs_remove_link(struct kobject * kobj, const char * name) sysfs_hash_and_remove(kobj->sd, name); } -static int sysfs_get_target_path(struct sysfs_dirent * parent_sd, - struct sysfs_dirent * target_sd, char *path) +static int sysfs_get_target_path(struct sysfs_dirent *parent_sd, + struct sysfs_dirent *target_sd, char *path) { - char * s; - int depth, size; + struct sysfs_dirent *base, *sd; + char *s = path; + int len = 0; + + /* go up to the root, stop at the base */ + base = parent_sd; + while (base->s_parent) { + sd = target_sd->s_parent; + while (sd->s_parent && base != sd) + sd = sd->s_parent; + + if (base == sd) + break; + + strcpy(s, "../"); + s += 3; + base = base->s_parent; + } + + /* determine end of target string for reverse fillup */ + sd = target_sd; + while (sd->s_parent && sd != base) { + len += strlen(sd->s_name) + 1; + sd = sd->s_parent; + } - depth = object_depth(parent_sd); - size = object_path_length(target_sd) + depth * 3 - 1; - if (size > PATH_MAX) + /* check limits */ + if (len < 2) + return -EINVAL; + len--; + if ((s - path) + len > PATH_MAX) return -ENAMETOOLONG; - pr_debug("%s: depth = %d, size = %d\n", __FUNCTION__, depth, size); + /* reverse fillup of target string from target to base */ + sd = target_sd; + while (sd->s_parent && sd != base) { + int slen = strlen(sd->s_name); - for (s = path; depth--; s += 3) - strcpy(s,"../"); + len -= slen; + strncpy(s + len, sd->s_name, slen); + if (len) + s[--len] = '/'; - fill_object_path(target_sd, path, size); - pr_debug("%s: path = '%s'\n", __FUNCTION__, path); + sd = sd->s_parent; + } return 0; } diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 7b74b60a68a47b26d3addf541b3440f23bd947ad..fb7171b1bd22e900349126212f8fceb4f997d8e8 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -319,7 +319,7 @@ struct acpi_bus_event { u32 data; }; -extern struct kset acpi_subsys; +extern struct kobject *acpi_kobj; extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int); /* * External Functions diff --git a/include/linux/device.h b/include/linux/device.h index 2e15822fe40931cb88eb627971f1a5db41f9c892..1880208964d6c9a4a75d332927a0ef3e23b19191 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -25,75 +25,69 @@ #include <asm/device.h> #define DEVICE_NAME_SIZE 50 -#define DEVICE_NAME_HALF __stringify(20) /* Less than half to accommodate slop */ +/* DEVICE_NAME_HALF is really less than half to accommodate slop */ +#define DEVICE_NAME_HALF __stringify(20) #define DEVICE_ID_SIZE 32 #define BUS_ID_SIZE KOBJ_NAME_LEN struct device; struct device_driver; +struct driver_private; struct class; struct class_device; struct bus_type; +struct bus_type_private; struct bus_attribute { struct attribute attr; - ssize_t (*show)(struct bus_type *, char * buf); - ssize_t (*store)(struct bus_type *, const char * buf, size_t count); + ssize_t (*show)(struct bus_type *bus, char *buf); + ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count); }; -#define BUS_ATTR(_name,_mode,_show,_store) \ -struct bus_attribute bus_attr_##_name = __ATTR(_name,_mode,_show,_store) +#define BUS_ATTR(_name, _mode, _show, _store) \ +struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store) extern int __must_check bus_create_file(struct bus_type *, struct bus_attribute *); extern void bus_remove_file(struct bus_type *, struct bus_attribute *); struct bus_type { - const char * name; - struct module * owner; + const char *name; + struct bus_attribute *bus_attrs; + struct device_attribute *dev_attrs; + struct driver_attribute *drv_attrs; - struct kset subsys; - struct kset drivers; - struct kset devices; - struct klist klist_devices; - struct klist klist_drivers; - - struct blocking_notifier_head bus_notifier; - - struct bus_attribute * bus_attrs; - struct device_attribute * dev_attrs; - struct driver_attribute * drv_attrs; - - int (*match)(struct device * dev, struct device_driver * drv); - int (*uevent)(struct device *dev, struct kobj_uevent_env *env); - int (*probe)(struct device * dev); - int (*remove)(struct device * dev); - void (*shutdown)(struct device * dev); + int (*match)(struct device *dev, struct device_driver *drv); + int (*uevent)(struct device *dev, struct kobj_uevent_env *env); + int (*probe)(struct device *dev); + int (*remove)(struct device *dev); + void (*shutdown)(struct device *dev); - int (*suspend)(struct device * dev, pm_message_t state); - int (*suspend_late)(struct device * dev, pm_message_t state); - int (*resume_early)(struct device * dev); - int (*resume)(struct device * dev); + int (*suspend)(struct device *dev, pm_message_t state); + int (*suspend_late)(struct device *dev, pm_message_t state); + int (*resume_early)(struct device *dev); + int (*resume)(struct device *dev); - unsigned int drivers_autoprobe:1; + struct bus_type_private *p; }; -extern int __must_check bus_register(struct bus_type * bus); -extern void bus_unregister(struct bus_type * bus); +extern int __must_check bus_register(struct bus_type *bus); +extern void bus_unregister(struct bus_type *bus); -extern int __must_check bus_rescan_devices(struct bus_type * bus); +extern int __must_check bus_rescan_devices(struct bus_type *bus); /* iterator helpers for buses */ -int bus_for_each_dev(struct bus_type * bus, struct device * start, void * data, - int (*fn)(struct device *, void *)); -struct device * bus_find_device(struct bus_type *bus, struct device *start, - void *data, int (*match)(struct device *, void *)); +int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, + int (*fn)(struct device *dev, void *data)); +struct device *bus_find_device(struct bus_type *bus, struct device *start, + void *data, + int (*match)(struct device *dev, void *data)); int __must_check bus_for_each_drv(struct bus_type *bus, - struct device_driver *start, void *data, - int (*fn)(struct device_driver *, void *)); + struct device_driver *start, void *data, + int (*fn)(struct device_driver *, void *)); /* * Bus notifiers: Get notified of addition/removal of devices @@ -118,111 +112,128 @@ extern int bus_unregister_notifier(struct bus_type *bus, #define BUS_NOTIFY_UNBIND_DRIVER 0x00000004 /* driver about to be unbound */ +extern struct kset *bus_get_kset(struct bus_type *bus); +extern struct klist *bus_get_device_klist(struct bus_type *bus); + struct device_driver { - const char * name; - struct bus_type * bus; + const char *name; + struct bus_type *bus; - struct kobject kobj; - struct klist klist_devices; - struct klist_node knode_bus; + struct module *owner; + const char *mod_name; /* used for built-in modules */ - struct module * owner; - const char * mod_name; /* used for built-in modules */ - struct module_kobject * mkobj; + int (*probe) (struct device *dev); + int (*remove) (struct device *dev); + void (*shutdown) (struct device *dev); + int (*suspend) (struct device *dev, pm_message_t state); + int (*resume) (struct device *dev); + struct attribute_group **groups; - int (*probe) (struct device * dev); - int (*remove) (struct device * dev); - void (*shutdown) (struct device * dev); - int (*suspend) (struct device * dev, pm_message_t state); - int (*resume) (struct device * dev); + struct driver_private *p; }; -extern int __must_check driver_register(struct device_driver * drv); -extern void driver_unregister(struct device_driver * drv); +extern int __must_check driver_register(struct device_driver *drv); +extern void driver_unregister(struct device_driver *drv); -extern struct device_driver * get_driver(struct device_driver * drv); -extern void put_driver(struct device_driver * drv); -extern struct device_driver *driver_find(const char *name, struct bus_type *bus); +extern struct device_driver *get_driver(struct device_driver *drv); +extern void put_driver(struct device_driver *drv); +extern struct device_driver *driver_find(const char *name, + struct bus_type *bus); extern int driver_probe_done(void); /* sysfs interface for exporting driver attributes */ struct driver_attribute { - struct attribute attr; - ssize_t (*show)(struct device_driver *, char * buf); - ssize_t (*store)(struct device_driver *, const char * buf, size_t count); + struct attribute attr; + ssize_t (*show)(struct device_driver *driver, char *buf); + ssize_t (*store)(struct device_driver *driver, const char *buf, + size_t count); }; -#define DRIVER_ATTR(_name,_mode,_show,_store) \ -struct driver_attribute driver_attr_##_name = __ATTR(_name,_mode,_show,_store) +#define DRIVER_ATTR(_name, _mode, _show, _store) \ +struct driver_attribute driver_attr_##_name = \ + __ATTR(_name, _mode, _show, _store) -extern int __must_check driver_create_file(struct device_driver *, - struct driver_attribute *); -extern void driver_remove_file(struct device_driver *, struct driver_attribute *); +extern int __must_check driver_create_file(struct device_driver *driver, + struct driver_attribute *attr); +extern void driver_remove_file(struct device_driver *driver, + struct driver_attribute *attr); -extern int __must_check driver_for_each_device(struct device_driver * drv, - struct device *start, void *data, - int (*fn)(struct device *, void *)); -struct device * driver_find_device(struct device_driver *drv, - struct device *start, void *data, - int (*match)(struct device *, void *)); +extern int __must_check driver_add_kobj(struct device_driver *drv, + struct kobject *kobj, + const char *fmt, ...); + +extern int __must_check driver_for_each_device(struct device_driver *drv, + struct device *start, + void *data, + int (*fn)(struct device *dev, + void *)); +struct device *driver_find_device(struct device_driver *drv, + struct device *start, void *data, + int (*match)(struct device *dev, void *data)); /* * device classes */ struct class { - const char * name; - struct module * owner; + const char *name; + struct module *owner; struct kset subsys; struct list_head children; struct list_head devices; struct list_head interfaces; struct kset class_dirs; - struct semaphore sem; /* locks both the children and interfaces lists */ - - struct class_attribute * class_attrs; - struct class_device_attribute * class_dev_attrs; - struct device_attribute * dev_attrs; + struct semaphore sem; /* locks children, devices, interfaces */ + struct class_attribute *class_attrs; + struct class_device_attribute *class_dev_attrs; + struct device_attribute *dev_attrs; - int (*uevent)(struct class_device *dev, struct kobj_uevent_env *env); - int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env); + int (*uevent)(struct class_device *dev, struct kobj_uevent_env *env); + int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env); - void (*release)(struct class_device *dev); - void (*class_release)(struct class *class); - void (*dev_release)(struct device *dev); + void (*release)(struct class_device *dev); + void (*class_release)(struct class *class); + void (*dev_release)(struct device *dev); - int (*suspend)(struct device *, pm_message_t state); - int (*resume)(struct device *); + int (*suspend)(struct device *dev, pm_message_t state); + int (*resume)(struct device *dev); }; -extern int __must_check class_register(struct class *); -extern void class_unregister(struct class *); +extern int __must_check class_register(struct class *class); +extern void class_unregister(struct class *class); +extern int class_for_each_device(struct class *class, void *data, + int (*fn)(struct device *dev, void *data)); +extern struct device *class_find_device(struct class *class, void *data, + int (*match)(struct device *, void *)); +extern struct class_device *class_find_child(struct class *class, void *data, + int (*match)(struct class_device *, void *)); struct class_attribute { - struct attribute attr; - ssize_t (*show)(struct class *, char * buf); - ssize_t (*store)(struct class *, const char * buf, size_t count); + struct attribute attr; + ssize_t (*show)(struct class *class, char *buf); + ssize_t (*store)(struct class *class, const char *buf, size_t count); }; -#define CLASS_ATTR(_name,_mode,_show,_store) \ -struct class_attribute class_attr_##_name = __ATTR(_name,_mode,_show,_store) +#define CLASS_ATTR(_name, _mode, _show, _store) \ +struct class_attribute class_attr_##_name = __ATTR(_name, _mode, _show, _store) -extern int __must_check class_create_file(struct class *, - const struct class_attribute *); -extern void class_remove_file(struct class *, const struct class_attribute *); +extern int __must_check class_create_file(struct class *class, + const struct class_attribute *attr); +extern void class_remove_file(struct class *class, + const struct class_attribute *attr); struct class_device_attribute { - struct attribute attr; - ssize_t (*show)(struct class_device *, char * buf); - ssize_t (*store)(struct class_device *, const char * buf, size_t count); + struct attribute attr; + ssize_t (*show)(struct class_device *, char *buf); + ssize_t (*store)(struct class_device *, const char *buf, size_t count); }; -#define CLASS_DEVICE_ATTR(_name,_mode,_show,_store) \ +#define CLASS_DEVICE_ATTR(_name, _mode, _show, _store) \ struct class_device_attribute class_device_attr_##_name = \ - __ATTR(_name,_mode,_show,_store) + __ATTR(_name, _mode, _show, _store) extern int __must_check class_device_create_file(struct class_device *, const struct class_device_attribute *); @@ -255,26 +266,24 @@ struct class_device { struct list_head node; struct kobject kobj; - struct class * class; /* required */ - dev_t devt; /* dev_t, creates the sysfs "dev" */ - struct device * dev; /* not necessary, but nice to have */ - void * class_data; /* class-specific data */ - struct class_device *parent; /* parent of this child device, if there is one */ - struct attribute_group ** groups; /* optional groups */ - - void (*release)(struct class_device *dev); - int (*uevent)(struct class_device *dev, struct kobj_uevent_env *env); - char class_id[BUS_ID_SIZE]; /* unique to this class */ + struct class *class; + dev_t devt; + struct device *dev; + void *class_data; + struct class_device *parent; + struct attribute_group **groups; + + void (*release)(struct class_device *dev); + int (*uevent)(struct class_device *dev, struct kobj_uevent_env *env); + char class_id[BUS_ID_SIZE]; }; -static inline void * -class_get_devdata (struct class_device *dev) +static inline void *class_get_devdata(struct class_device *dev) { return dev->class_data; } -static inline void -class_set_devdata (struct class_device *dev, void *data) +static inline void class_set_devdata(struct class_device *dev, void *data) { dev->class_data = data; } @@ -286,10 +295,10 @@ extern void class_device_initialize(struct class_device *); extern int __must_check class_device_add(struct class_device *); extern void class_device_del(struct class_device *); -extern struct class_device * class_device_get(struct class_device *); +extern struct class_device *class_device_get(struct class_device *); extern void class_device_put(struct class_device *); -extern void class_device_remove_file(struct class_device *, +extern void class_device_remove_file(struct class_device *, const struct class_device_attribute *); extern int __must_check class_device_create_bin_file(struct class_device *, struct bin_attribute *); @@ -316,7 +325,7 @@ extern struct class_device *class_device_create(struct class *cls, dev_t devt, struct device *device, const char *fmt, ...) - __attribute__((format(printf,5,6))); + __attribute__((format(printf, 5, 6))); extern void class_device_destroy(struct class *cls, dev_t devt); /* @@ -333,8 +342,8 @@ struct device_type { struct attribute_group **groups; int (*uevent)(struct device *dev, struct kobj_uevent_env *env); void (*release)(struct device *dev); - int (*suspend)(struct device * dev, pm_message_t state); - int (*resume)(struct device * dev); + int (*suspend)(struct device *dev, pm_message_t state); + int (*resume)(struct device *dev); }; /* interface for exporting device attributes */ @@ -346,18 +355,19 @@ struct device_attribute { const char *buf, size_t count); }; -#define DEVICE_ATTR(_name,_mode,_show,_store) \ -struct device_attribute dev_attr_##_name = __ATTR(_name,_mode,_show,_store) +#define DEVICE_ATTR(_name, _mode, _show, _store) \ +struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store) extern int __must_check device_create_file(struct device *device, - struct device_attribute * entry); -extern void device_remove_file(struct device * dev, struct device_attribute * attr); + struct device_attribute *entry); +extern void device_remove_file(struct device *dev, + struct device_attribute *attr); extern int __must_check device_create_bin_file(struct device *dev, struct bin_attribute *attr); extern void device_remove_bin_file(struct device *dev, struct bin_attribute *attr); extern int device_schedule_callback_owner(struct device *dev, - void (*func)(struct device *), struct module *owner); + void (*func)(struct device *dev), struct module *owner); /* This is a macro to avoid include problems with THIS_MODULE */ #define device_schedule_callback(dev, func) \ @@ -368,21 +378,21 @@ typedef void (*dr_release_t)(struct device *dev, void *res); typedef int (*dr_match_t)(struct device *dev, void *res, void *match_data); #ifdef CONFIG_DEBUG_DEVRES -extern void * __devres_alloc(dr_release_t release, size_t size, gfp_t gfp, +extern void *__devres_alloc(dr_release_t release, size_t size, gfp_t gfp, const char *name); #define devres_alloc(release, size, gfp) \ __devres_alloc(release, size, gfp, #release) #else -extern void * devres_alloc(dr_release_t release, size_t size, gfp_t gfp); +extern void *devres_alloc(dr_release_t release, size_t size, gfp_t gfp); #endif extern void devres_free(void *res); extern void devres_add(struct device *dev, void *res); -extern void * devres_find(struct device *dev, dr_release_t release, - dr_match_t match, void *match_data); -extern void * devres_get(struct device *dev, void *new_res, +extern void *devres_find(struct device *dev, dr_release_t release, dr_match_t match, void *match_data); -extern void * devres_remove(struct device *dev, dr_release_t release, - dr_match_t match, void *match_data); +extern void *devres_get(struct device *dev, void *new_res, + dr_match_t match, void *match_data); +extern void *devres_remove(struct device *dev, dr_release_t release, + dr_match_t match, void *match_data); extern int devres_destroy(struct device *dev, dr_release_t release, dr_match_t match, void *match_data); @@ -399,7 +409,7 @@ extern void devm_kfree(struct device *dev, void *p); struct device { struct klist klist_children; - struct klist_node knode_parent; /* node in sibling list */ + struct klist_node knode_parent; /* node in sibling list */ struct klist_node knode_driver; struct klist_node knode_bus; struct device *parent; @@ -414,7 +424,7 @@ struct device { * its driver. */ - struct bus_type * bus; /* type of bus device is on */ + struct bus_type *bus; /* type of bus device is on */ struct device_driver *driver; /* which driver has allocated this device */ void *driver_data; /* data private to the driver */ @@ -445,10 +455,10 @@ struct device { /* class_device migration path */ struct list_head node; struct class *class; - dev_t devt; /* dev_t, creates the sysfs "dev" */ + dev_t devt; /* dev_t, creates the sysfs "dev" */ struct attribute_group **groups; /* optional groups */ - void (*release)(struct device * dev); + void (*release)(struct device *dev); }; #ifdef CONFIG_NUMA @@ -470,14 +480,12 @@ static inline void set_dev_node(struct device *dev, int node) } #endif -static inline void * -dev_get_drvdata (struct device *dev) +static inline void *dev_get_drvdata(struct device *dev) { return dev->driver_data; } -static inline void -dev_set_drvdata (struct device *dev, void *data) +static inline void dev_set_drvdata(struct device *dev, void *data) { dev->driver_data = data; } @@ -492,15 +500,15 @@ void driver_init(void); /* * High level routines for use by the bus drivers */ -extern int __must_check device_register(struct device * dev); -extern void device_unregister(struct device * dev); -extern void device_initialize(struct device * dev); -extern int __must_check device_add(struct device * dev); -extern void device_del(struct device * dev); -extern int device_for_each_child(struct device *, void *, - int (*fn)(struct device *, void *)); -extern struct device *device_find_child(struct device *, void *data, - int (*match)(struct device *, void *)); +extern int __must_check device_register(struct device *dev); +extern void device_unregister(struct device *dev); +extern void device_initialize(struct device *dev); +extern int __must_check device_add(struct device *dev); +extern void device_del(struct device *dev); +extern int device_for_each_child(struct device *dev, void *data, + int (*fn)(struct device *dev, void *data)); +extern struct device *device_find_child(struct device *dev, void *data, + int (*match)(struct device *dev, void *data)); extern int device_rename(struct device *dev, char *new_name); extern int device_move(struct device *dev, struct device *new_parent); @@ -509,8 +517,8 @@ extern int device_move(struct device *dev, struct device *new_parent); * for information on use. */ extern int __must_check device_bind_driver(struct device *dev); -extern void device_release_driver(struct device * dev); -extern int __must_check device_attach(struct device * dev); +extern void device_release_driver(struct device *dev); +extern int __must_check device_attach(struct device *dev); extern int __must_check driver_attach(struct device_driver *drv); extern int __must_check device_reprobe(struct device *dev); @@ -519,8 +527,16 @@ extern int __must_check device_reprobe(struct device *dev); */ extern struct device *device_create(struct class *cls, struct device *parent, dev_t devt, const char *fmt, ...) - __attribute__((format(printf,4,5))); + __attribute__((format(printf, 4, 5))); extern void device_destroy(struct class *cls, dev_t devt); +#ifdef CONFIG_PM_SLEEP +extern void destroy_suspended_device(struct class *cls, dev_t devt); +#else /* !CONFIG_PM_SLEEP */ +static inline void destroy_suspended_device(struct class *cls, dev_t devt) +{ + device_destroy(cls, devt); +} +#endif /* !CONFIG_PM_SLEEP */ /* * Platform "fixup" functions - allow the platform to have their say @@ -528,17 +544,17 @@ extern void device_destroy(struct class *cls, dev_t devt); * know about. */ /* Notify platform of device discovery */ -extern int (*platform_notify)(struct device * dev); +extern int (*platform_notify)(struct device *dev); -extern int (*platform_notify_remove)(struct device * dev); +extern int (*platform_notify_remove)(struct device *dev); /** * get_device - atomically increment the reference count for the device. * */ -extern struct device * get_device(struct device * dev); -extern void put_device(struct device * dev); +extern struct device *get_device(struct device *dev); +extern void put_device(struct device *dev); /* drivers/base/power/shutdown.c */ @@ -547,22 +563,33 @@ extern void device_shutdown(void); /* drivers/base/sys.c */ extern void sysdev_shutdown(void); - -/* drivers/base/firmware.c */ -extern int __must_check firmware_register(struct kset *); -extern void firmware_unregister(struct kset *); - /* debugging and troubleshooting/diagnostic helpers. */ extern const char *dev_driver_string(struct device *dev); #define dev_printk(level, dev, format, arg...) \ - printk(level "%s %s: " format , dev_driver_string(dev) , (dev)->bus_id , ## arg) + printk(level "%s %s: " format , dev_driver_string(dev) , \ + (dev)->bus_id , ## arg) + +#define dev_emerg(dev, format, arg...) \ + dev_printk(KERN_EMERG , dev , format , ## arg) +#define dev_alert(dev, format, arg...) \ + dev_printk(KERN_ALERT , dev , format , ## arg) +#define dev_crit(dev, format, arg...) \ + dev_printk(KERN_CRIT , dev , format , ## arg) +#define dev_err(dev, format, arg...) \ + dev_printk(KERN_ERR , dev , format , ## arg) +#define dev_warn(dev, format, arg...) \ + dev_printk(KERN_WARNING , dev , format , ## arg) +#define dev_notice(dev, format, arg...) \ + dev_printk(KERN_NOTICE , dev , format , ## arg) +#define dev_info(dev, format, arg...) \ + dev_printk(KERN_INFO , dev , format , ## arg) #ifdef DEBUG #define dev_dbg(dev, format, arg...) \ dev_printk(KERN_DEBUG , dev , format , ## arg) #else static inline int __attribute__ ((format (printf, 2, 3))) -dev_dbg(struct device * dev, const char * fmt, ...) +dev_dbg(struct device *dev, const char *fmt, ...) { return 0; } @@ -572,21 +599,12 @@ dev_dbg(struct device * dev, const char * fmt, ...) #define dev_vdbg dev_dbg #else static inline int __attribute__ ((format (printf, 2, 3))) -dev_vdbg(struct device * dev, const char * fmt, ...) +dev_vdbg(struct device *dev, const char *fmt, ...) { return 0; } #endif -#define dev_err(dev, format, arg...) \ - dev_printk(KERN_ERR , dev , format , ## arg) -#define dev_info(dev, format, arg...) \ - dev_printk(KERN_INFO , dev , format , ## arg) -#define dev_warn(dev, format, arg...) \ - dev_printk(KERN_WARNING , dev , format , ## arg) -#define dev_notice(dev, format, arg...) \ - dev_printk(KERN_NOTICE , dev , format , ## arg) - /* Create alias, so I can be autoloaded. */ #define MODULE_ALIAS_CHARDEV(major,minor) \ MODULE_ALIAS("char-major-" __stringify(major) "-" __stringify(minor)) diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index a3b6035b6c860c506c7c5c2d923cdc8444901ad6..55c9a6952f447c6284a5b75b88ac9696ddc89214 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -132,7 +132,7 @@ struct dma_chan { /* sysfs */ int chan_id; - struct class_device class_dev; + struct device dev; struct kref refcount; int slow_ref; @@ -142,6 +142,7 @@ struct dma_chan { struct dma_chan_percpu *local; }; +#define to_dma_chan(p) container_of(p, struct dma_chan, dev) void dma_chan_cleanup(struct kref *kref); diff --git a/include/linux/fs.h b/include/linux/fs.h index b3ec4a496d64faa3a380827abed7b54d9d8bd7da..21398a5d688d3e188325822c781ae19e8c67d6b9 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1476,7 +1476,7 @@ extern void drop_collected_mounts(struct vfsmount *); extern int vfs_statfs(struct dentry *, struct kstatfs *); /* /sys/fs */ -extern struct kset fs_subsys; +extern struct kobject *fs_kobj; #define FLOCK_VERIFY_READ 1 #define FLOCK_VERIFY_WRITE 2 diff --git a/include/linux/genhd.h b/include/linux/genhd.h index a47b8025d39935c18a66db9cc975a58fe8f85dda..1dbea0ac5693049885c7c8ec33ec158dad1cb4bc 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -10,9 +10,19 @@ */ #include <linux/types.h> +#include <linux/kdev_t.h> #ifdef CONFIG_BLOCK +#define kobj_to_dev(k) container_of(k, struct device, kobj) +#define dev_to_disk(device) container_of(device, struct gendisk, dev) +#define dev_to_part(device) container_of(device, struct hd_struct, dev) + +extern struct device_type disk_type; +extern struct device_type part_type; +extern struct kobject *block_depr; +extern struct class block_class; + enum { /* These three have identical behaviour; use the second one if DOS FDISK gets confused about extended/logical partitions starting past cylinder 1023. */ @@ -84,7 +94,7 @@ struct partition { struct hd_struct { sector_t start_sect; sector_t nr_sects; - struct kobject kobj; + struct device dev; struct kobject *holder_dir; unsigned ios[2], sectors[2]; /* READs and WRITEs */ int policy, partno; @@ -117,15 +127,14 @@ struct gendisk { * disks that can't be partitioned. */ char disk_name[32]; /* name of major driver */ struct hd_struct **part; /* [indexed by minor] */ - int part_uevent_suppress; struct block_device_operations *fops; struct request_queue *queue; void *private_data; sector_t capacity; int flags; - struct device *driverfs_dev; - struct kobject kobj; + struct device *driverfs_dev; // FIXME: remove + struct device dev; struct kobject *holder_dir; struct kobject *slave_dir; @@ -143,13 +152,6 @@ struct gendisk { struct work_struct async_notify; }; -/* Structure for sysfs attributes on block devices */ -struct disk_attribute { - struct attribute attr; - ssize_t (*show)(struct gendisk *, char *); - ssize_t (*store)(struct gendisk *, const char *, size_t); -}; - /* * Macros to operate on percpu disk statistics: * @@ -411,7 +413,8 @@ struct unixware_disklabel { #define ADDPART_FLAG_RAID 1 #define ADDPART_FLAG_WHOLEDISK 2 -char *disk_name (struct gendisk *hd, int part, char *buf); +extern dev_t blk_lookup_devt(const char *name); +extern char *disk_name (struct gendisk *hd, int part, char *buf); extern int rescan_partitions(struct gendisk *disk, struct block_device *bdev); extern void add_partition(struct gendisk *, int, sector_t, sector_t, int); @@ -423,12 +426,12 @@ extern struct gendisk *alloc_disk(int minors); extern struct kobject *get_disk(struct gendisk *disk); extern void put_disk(struct gendisk *disk); extern void genhd_media_change_notify(struct gendisk *disk); -extern void blk_register_region(dev_t dev, unsigned long range, +extern void blk_register_region(dev_t devt, unsigned long range, struct module *module, struct kobject *(*probe)(dev_t, int *, void *), int (*lock)(dev_t, void *), void *data); -extern void blk_unregister_region(dev_t dev, unsigned long range); +extern void blk_unregister_region(dev_t devt, unsigned long range); static inline struct block_device *bdget_disk(struct gendisk *disk, int index) { @@ -441,6 +444,12 @@ static inline struct block_device *bdget_disk(struct gendisk *disk, int index) static inline void printk_all_partitions(void) { } +static inline dev_t blk_lookup_devt(const char *name) +{ + dev_t devt = MKDEV(0, 0); + return devt; +} + #endif /* CONFIG_BLOCK */ #endif diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 4a0d27f475d7485ba13ee691b9b3978b7a3ed9a8..caa3f411f15d0c48958e40d5369b4e16b9456b15 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -3,15 +3,14 @@ * * Copyright (c) 2002-2003 Patrick Mochel * Copyright (c) 2002-2003 Open Source Development Labs - * Copyright (c) 2006-2007 Greg Kroah-Hartman <greg@kroah.com> - * Copyright (c) 2006-2007 Novell Inc. + * Copyright (c) 2006-2008 Greg Kroah-Hartman <greg@kroah.com> + * Copyright (c) 2006-2008 Novell Inc. * * This file is released under the GPLv2. * - * * Please read Documentation/kobject.txt before using the kobject * interface, ESPECIALLY the parts about reference counts and object - * destructors. + * destructors. */ #ifndef _KOBJECT_H_ @@ -61,48 +60,54 @@ enum kobject_action { }; struct kobject { - const char * k_name; + const char *name; struct kref kref; struct list_head entry; - struct kobject * parent; - struct kset * kset; - struct kobj_type * ktype; - struct sysfs_dirent * sd; + struct kobject *parent; + struct kset *kset; + struct kobj_type *ktype; + struct sysfs_dirent *sd; + unsigned int state_initialized:1; + unsigned int state_in_sysfs:1; + unsigned int state_add_uevent_sent:1; + unsigned int state_remove_uevent_sent:1; }; -extern int kobject_set_name(struct kobject *, const char *, ...) - __attribute__((format(printf,2,3))); +extern int kobject_set_name(struct kobject *kobj, const char *name, ...) + __attribute__((format(printf, 2, 3))); -static inline const char * kobject_name(const struct kobject * kobj) +static inline const char *kobject_name(const struct kobject *kobj) { - return kobj->k_name; + return kobj->name; } -extern void kobject_init(struct kobject *); -extern void kobject_cleanup(struct kobject *); +extern void kobject_init(struct kobject *kobj, struct kobj_type *ktype); +extern int __must_check kobject_add(struct kobject *kobj, + struct kobject *parent, + const char *fmt, ...); +extern int __must_check kobject_init_and_add(struct kobject *kobj, + struct kobj_type *ktype, + struct kobject *parent, + const char *fmt, ...); + +extern void kobject_del(struct kobject *kobj); -extern int __must_check kobject_add(struct kobject *); -extern void kobject_del(struct kobject *); +extern struct kobject * __must_check kobject_create(void); +extern struct kobject * __must_check kobject_create_and_add(const char *name, + struct kobject *parent); extern int __must_check kobject_rename(struct kobject *, const char *new_name); extern int __must_check kobject_move(struct kobject *, struct kobject *); -extern int __must_check kobject_register(struct kobject *); -extern void kobject_unregister(struct kobject *); - -extern struct kobject * kobject_get(struct kobject *); -extern void kobject_put(struct kobject *); - -extern struct kobject *kobject_kset_add_dir(struct kset *kset, - struct kobject *, const char *); -extern struct kobject *kobject_add_dir(struct kobject *, const char *); +extern struct kobject *kobject_get(struct kobject *kobj); +extern void kobject_put(struct kobject *kobj); -extern char * kobject_get_path(struct kobject *, gfp_t); +extern char *kobject_get_path(struct kobject *kobj, gfp_t flag); struct kobj_type { - void (*release)(struct kobject *); - struct sysfs_ops * sysfs_ops; - struct attribute ** default_attrs; + void (*release)(struct kobject *kobj); + struct sysfs_ops *sysfs_ops; + struct attribute **default_attrs; }; struct kobj_uevent_env { @@ -119,6 +124,16 @@ struct kset_uevent_ops { struct kobj_uevent_env *env); }; +struct kobj_attribute { + struct attribute attr; + ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr, + char *buf); + ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count); +}; + +extern struct sysfs_ops kobj_sysfs_ops; + /** * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem. * @@ -128,7 +143,6 @@ struct kset_uevent_ops { * define the attribute callbacks and other common events that happen to * a kobject. * - * @ktype: the struct kobj_type for this specific kset * @list: the list of all kobjects for this kset * @list_lock: a lock for iterating over the kobjects * @kobj: the embedded kobject for this kset (recursion, isn't it fun...) @@ -138,99 +152,49 @@ struct kset_uevent_ops { * desired. */ struct kset { - struct kobj_type *ktype; - struct list_head list; - spinlock_t list_lock; - struct kobject kobj; - struct kset_uevent_ops *uevent_ops; + struct list_head list; + spinlock_t list_lock; + struct kobject kobj; + struct kset_uevent_ops *uevent_ops; }; +extern void kset_init(struct kset *kset); +extern int __must_check kset_register(struct kset *kset); +extern void kset_unregister(struct kset *kset); +extern struct kset * __must_check kset_create_and_add(const char *name, + struct kset_uevent_ops *u, + struct kobject *parent_kobj); -extern void kset_init(struct kset * k); -extern int __must_check kset_add(struct kset * k); -extern int __must_check kset_register(struct kset * k); -extern void kset_unregister(struct kset * k); - -static inline struct kset * to_kset(struct kobject * kobj) +static inline struct kset *to_kset(struct kobject *kobj) { - return kobj ? container_of(kobj,struct kset,kobj) : NULL; + return kobj ? container_of(kobj, struct kset, kobj) : NULL; } -static inline struct kset * kset_get(struct kset * k) +static inline struct kset *kset_get(struct kset *k) { return k ? to_kset(kobject_get(&k->kobj)) : NULL; } -static inline void kset_put(struct kset * k) +static inline void kset_put(struct kset *k) { kobject_put(&k->kobj); } -static inline struct kobj_type * get_ktype(struct kobject * k) +static inline struct kobj_type *get_ktype(struct kobject *kobj) { - if (k->kset && k->kset->ktype) - return k->kset->ktype; - else - return k->ktype; + return kobj->ktype; } -extern struct kobject * kset_find_obj(struct kset *, const char *); - - -/* - * Use this when initializing an embedded kset with no other - * fields to initialize. - */ -#define set_kset_name(str) .kset = { .kobj = { .k_name = str } } - - -#define decl_subsys(_name,_type,_uevent_ops) \ -struct kset _name##_subsys = { \ - .kobj = { .k_name = __stringify(_name) }, \ - .ktype = _type, \ - .uevent_ops =_uevent_ops, \ -} -#define decl_subsys_name(_varname,_name,_type,_uevent_ops) \ -struct kset _varname##_subsys = { \ - .kobj = { .k_name = __stringify(_name) }, \ - .ktype = _type, \ - .uevent_ops =_uevent_ops, \ -} - -/* The global /sys/kernel/ subsystem for people to chain off of */ -extern struct kset kernel_subsys; -/* The global /sys/hypervisor/ subsystem */ -extern struct kset hypervisor_subsys; - -/* - * Helpers for setting the kset of registered objects. - * Often, a registered object belongs to a kset embedded in a - * subsystem. These do no magic, just make the resulting code - * easier to follow. - */ - -/** - * kobj_set_kset_s(obj,subsys) - set kset for embedded kobject. - * @obj: ptr to some object type. - * @subsys: a subsystem object (not a ptr). - * - * Can be used for any object type with an embedded ->kobj. - */ - -#define kobj_set_kset_s(obj,subsys) \ - (obj)->kobj.kset = &(subsys) - -extern int __must_check subsystem_register(struct kset *); -extern void subsystem_unregister(struct kset *); - -struct subsys_attribute { - struct attribute attr; - ssize_t (*show)(struct kset *, char *); - ssize_t (*store)(struct kset *, const char *, size_t); -}; +extern struct kobject *kset_find_obj(struct kset *, const char *); -extern int __must_check subsys_create_file(struct kset *, - struct subsys_attribute *); +/* The global /sys/kernel/ kobject for people to chain off of */ +extern struct kobject *kernel_kobj; +/* The global /sys/hypervisor/ kobject for people to chain off of */ +extern struct kobject *hypervisor_kobj; +/* The global /sys/power/ kobject for people to chain off of */ +extern struct kobject *power_kobj; +/* The global /sys/firmware/ kobject for people to chain off of */ +extern struct kobject *firmware_kobj; #if defined(CONFIG_HOTPLUG) int kobject_uevent(struct kobject *kobj, enum kobject_action action); @@ -243,18 +207,20 @@ int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...) int kobject_action_type(const char *buf, size_t count, enum kobject_action *type); #else -static inline int kobject_uevent(struct kobject *kobj, enum kobject_action action) +static inline int kobject_uevent(struct kobject *kobj, + enum kobject_action action) { return 0; } static inline int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, char *envp[]) { return 0; } -static inline int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...) +static inline int add_uevent_var(struct kobj_uevent_env *env, + const char *format, ...) { return 0; } static inline int kobject_action_type(const char *buf, size_t count, - enum kobject_action *type) + enum kobject_action *type) { return -EINVAL; } #endif diff --git a/include/linux/kref.h b/include/linux/kref.h index 6fee3539893f6f93d5634ec099f5741e4d1ccb95..5d185635786e129a35c28f475fdbb879cf78558b 100644 --- a/include/linux/kref.h +++ b/include/linux/kref.h @@ -24,6 +24,7 @@ struct kref { atomic_t refcount; }; +void kref_set(struct kref *kref, int num); void kref_init(struct kref *kref); void kref_get(struct kref *kref); int kref_put(struct kref *kref, void (*release) (struct kref *kref)); diff --git a/include/linux/module.h b/include/linux/module.h index 2cbc0b87e329d30d0ec72b03c83f5d7f123b8a05..c97bdb7eb957cdd71e625ac9cf66862132d153da 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -574,7 +574,9 @@ struct device_driver; #ifdef CONFIG_SYSFS struct module; -extern struct kset module_subsys; +extern struct kset *module_kset; +extern struct kobj_type module_ktype; +extern int module_sysfs_initialized; int mod_sysfs_init(struct module *mod); int mod_sysfs_setup(struct module *mod, @@ -607,21 +609,6 @@ static inline void module_remove_modinfo_attrs(struct module *mod) #endif /* CONFIG_SYSFS */ -#if defined(CONFIG_SYSFS) && defined(CONFIG_MODULES) - -void module_add_driver(struct module *mod, struct device_driver *drv); -void module_remove_driver(struct device_driver *drv); - -#else /* not both CONFIG_SYSFS && CONFIG_MODULES */ - -static inline void module_add_driver(struct module *mod, struct device_driver *drv) -{ } - -static inline void module_remove_driver(struct device_driver *drv) -{ } - -#endif - #define symbol_request(x) try_then_request_module(symbol_get(x), "symbol:" #x) /* BELOW HERE ALL THESE ARE OBSOLETE AND WILL VANISH */ diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h index ab4cb6ecd47c3132c2393db1b290ea9965f3d96a..8f67e8f2a3cc0c0e24d32ebd77cde24bb94281a5 100644 --- a/include/linux/pci_hotplug.h +++ b/include/linux/pci_hotplug.h @@ -174,7 +174,7 @@ extern int pci_hp_register (struct hotplug_slot *slot); extern int pci_hp_deregister (struct hotplug_slot *slot); extern int __must_check pci_hp_change_slot_info (struct hotplug_slot *slot, struct hotplug_slot_info *info); -extern struct kset pci_hotplug_slots_subsys; +extern struct kset *pci_hotplug_slots_kset; /* PCI Setting Record (Type 0) */ struct hpp_type0 { diff --git a/include/linux/pktcdvd.h b/include/linux/pktcdvd.h index 5ea4f05683f6c838df23f48c2b8381a054ae7938..04b4d7330e6db16dab77d2317a8754fded181dce 100644 --- a/include/linux/pktcdvd.h +++ b/include/linux/pktcdvd.h @@ -290,7 +290,7 @@ struct pktcdvd_device int write_congestion_off; int write_congestion_on; - struct class_device *clsdev; /* sysfs pktcdvd[0-7] class dev */ + struct device *dev; /* sysfs pktcdvd[0-7] dev */ struct pktcdvd_kobj *kobj_stat; /* sysfs pktcdvd[0-7]/stat/ */ struct pktcdvd_kobj *kobj_wqueue; /* sysfs pktcdvd[0-7]/write_queue/ */ diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index e80804316cdb2e9c78c3ec15ab26435e056bd6bb..3261681c82a45bb4ec68551bd6bb40bbef1935e3 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -35,7 +35,7 @@ extern struct resource *platform_get_resource_byname(struct platform_device *, u extern int platform_get_irq_byname(struct platform_device *, char *); extern int platform_add_devices(struct platform_device **, int); -extern struct platform_device *platform_device_register_simple(char *, int id, +extern struct platform_device *platform_device_register_simple(const char *, int id, struct resource *, unsigned int); extern struct platform_device *platform_device_alloc(const char *name, int id); diff --git a/include/linux/sched.h b/include/linux/sched.h index cc14656f86829abb4dbb9d5329d5eabeaecbbcb1..d6eacda765ca76a8db94b1d6834652d5be875217 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -552,18 +552,13 @@ struct user_struct { #ifdef CONFIG_FAIR_USER_SCHED struct task_group *tg; #ifdef CONFIG_SYSFS - struct kset kset; - struct subsys_attribute user_attr; + struct kobject kobj; struct work_struct work; #endif #endif }; -#ifdef CONFIG_FAIR_USER_SCHED -extern int uids_kobject_init(void); -#else -static inline int uids_kobject_init(void) { return 0; } -#endif +extern int uids_sysfs_init(void); extern struct user_struct *find_user(uid_t); diff --git a/include/linux/sysdev.h b/include/linux/sysdev.h index e285746588d68baf4dccc894e70768005342e04a..f752e73bf977e98381b95070096522c84e2ed5a1 100644 --- a/include/linux/sysdev.h +++ b/include/linux/sysdev.h @@ -29,6 +29,7 @@ struct sys_device; struct sysdev_class { + const char *name; struct list_head drivers; /* Default operations for these types of devices */ diff --git a/include/linux/tifm.h b/include/linux/tifm.h index 6b3a31805c72ff2e5d450697e15afc5e507d2599..2096b76d0cee68efe8cd91571e69da3c36bffd2c 100644 --- a/include/linux/tifm.h +++ b/include/linux/tifm.h @@ -120,7 +120,7 @@ struct tifm_adapter { struct completion *finish_me; struct work_struct media_switcher; - struct class_device cdev; + struct device dev; void (*eject)(struct tifm_adapter *fm, struct tifm_dev *sock); diff --git a/include/linux/uio_driver.h b/include/linux/uio_driver.h index 44c28e94df505f86b9274904d87f98925d589724..973386d439da24ffef58636347b3463c5aa038b8 100644 --- a/include/linux/uio_driver.h +++ b/include/linux/uio_driver.h @@ -18,20 +18,22 @@ #include <linux/fs.h> #include <linux/interrupt.h> +struct uio_map; + /** * struct uio_mem - description of a UIO memory region - * @kobj: kobject for this mapping * @addr: address of the device's memory * @size: size of IO * @memtype: type of memory addr points to * @internal_addr: ioremap-ped version of addr, for driver internal use + * @map: for use by the UIO core only. */ struct uio_mem { - struct kobject kobj; unsigned long addr; unsigned long size; int memtype; void __iomem *internal_addr; + struct uio_map *map; }; #define MAX_UIO_MAPS 5 diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 11f39606e7d94c64c1a63c6e5772dbca944a538c..cfbd38fe299825f7101925860abc70c08d7f8dbb 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -1026,7 +1026,7 @@ struct ib_device { struct module *owner; struct class_device class_dev; - struct kobject ports_parent; + struct kobject *ports_parent; struct list_head port_list; enum { diff --git a/init/Kconfig b/init/Kconfig index b9d11a899b8861576be26f883882c969d170701f..f5becd2a12f6eaf02ed9a3f8c866c5cdcfb4838f 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -363,6 +363,7 @@ config CGROUP_CPUACCT config SYSFS_DEPRECATED bool "Create deprecated sysfs files" + depends on SYSFS default y help This option creates deprecated symlinks such as the diff --git a/init/do_mounts.c b/init/do_mounts.c index 4efa1e5385e3a1b110b29b46ceccedf36a8c4138..2ae5b84623992719c511256445876f15ce73f76b 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -55,69 +55,6 @@ static int __init readwrite(char *str) __setup("ro", readonly); __setup("rw", readwrite); -static dev_t try_name(char *name, int part) -{ - char path[64]; - char buf[32]; - int range; - dev_t res; - char *s; - int len; - int fd; - unsigned int maj, min; - - /* read device number from .../dev */ - - sprintf(path, "/sys/block/%s/dev", name); - fd = sys_open(path, 0, 0); - if (fd < 0) - goto fail; - len = sys_read(fd, buf, 32); - sys_close(fd); - if (len <= 0 || len == 32 || buf[len - 1] != '\n') - goto fail; - buf[len - 1] = '\0'; - if (sscanf(buf, "%u:%u", &maj, &min) == 2) { - /* - * Try the %u:%u format -- see print_dev_t() - */ - res = MKDEV(maj, min); - if (maj != MAJOR(res) || min != MINOR(res)) - goto fail; - } else { - /* - * Nope. Try old-style "0321" - */ - res = new_decode_dev(simple_strtoul(buf, &s, 16)); - if (*s) - goto fail; - } - - /* if it's there and we are not looking for a partition - that's it */ - if (!part) - return res; - - /* otherwise read range from .../range */ - sprintf(path, "/sys/block/%s/range", name); - fd = sys_open(path, 0, 0); - if (fd < 0) - goto fail; - len = sys_read(fd, buf, 32); - sys_close(fd); - if (len <= 0 || len == 32 || buf[len - 1] != '\n') - goto fail; - buf[len - 1] = '\0'; - range = simple_strtoul(buf, &s, 10); - if (*s) - goto fail; - - /* if partition is within range - we got it */ - if (part < range) - return res + part; -fail: - return 0; -} - /* * Convert a name into device number. We accept the following variants: * @@ -129,12 +66,10 @@ static dev_t try_name(char *name, int part) * 5) /dev/<disk_name>p<decimal> - same as the above, that form is * used when disk name of partitioned disk ends on a digit. * - * If name doesn't have fall into the categories above, we return 0. - * Sysfs is used to check if something is a disk name - it has - * all known disks under bus/block/devices. If the disk name - * contains slashes, name of sysfs node has them replaced with - * bangs. try_name() does the actual checks, assuming that sysfs - * is mounted on rootfs /sys. + * If name doesn't have fall into the categories above, we return (0,0). + * block_class is used to check if something is a disk name. If the disk + * name contains slashes, the device name has them replaced with + * bangs. */ dev_t name_to_dev_t(char *name) @@ -142,13 +77,6 @@ dev_t name_to_dev_t(char *name) char s[32]; char *p; dev_t res = 0; - int part; - -#ifdef CONFIG_SYSFS - int mkdir_err = sys_mkdir("/sys", 0700); - if (sys_mount("sysfs", "/sys", "sysfs", 0, NULL) < 0) - goto out; -#endif if (strncmp(name, "/dev/", 5) != 0) { unsigned maj, min; @@ -164,6 +92,7 @@ dev_t name_to_dev_t(char *name) } goto done; } + name += 5; res = Root_NFS; if (strcmp(name, "nfs") == 0) @@ -178,35 +107,14 @@ dev_t name_to_dev_t(char *name) for (p = s; *p; p++) if (*p == '/') *p = '!'; - res = try_name(s, 0); + res = blk_lookup_devt(s); if (res) goto done; - while (p > s && isdigit(p[-1])) - p--; - if (p == s || !*p || *p == '0') - goto fail; - part = simple_strtoul(p, NULL, 10); - *p = '\0'; - res = try_name(s, part); - if (res) - goto done; - - if (p < s + 2 || !isdigit(p[-2]) || p[-1] != 'p') - goto fail; - p[-1] = '\0'; - res = try_name(s, part); +fail: + return 0; done: -#ifdef CONFIG_SYSFS - sys_umount("/sys", 0); -out: - if (!mkdir_err) - sys_rmdir("/sys"); -#endif return res; -fail: - res = 0; - goto done; } static int __init root_dev_setup(char *line) diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c index 65daa5373ca6354afc0c575c1938ed1e9a08c300..e53bc30e9ba5aa8b55311fd6700191b0f21a9597 100644 --- a/kernel/ksysfs.c +++ b/kernel/ksysfs.c @@ -17,30 +17,34 @@ #include <linux/sched.h> #define KERNEL_ATTR_RO(_name) \ -static struct subsys_attribute _name##_attr = __ATTR_RO(_name) +static struct kobj_attribute _name##_attr = __ATTR_RO(_name) #define KERNEL_ATTR_RW(_name) \ -static struct subsys_attribute _name##_attr = \ +static struct kobj_attribute _name##_attr = \ __ATTR(_name, 0644, _name##_show, _name##_store) #if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET) /* current uevent sequence number */ -static ssize_t uevent_seqnum_show(struct kset *kset, char *page) +static ssize_t uevent_seqnum_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { - return sprintf(page, "%llu\n", (unsigned long long)uevent_seqnum); + return sprintf(buf, "%llu\n", (unsigned long long)uevent_seqnum); } KERNEL_ATTR_RO(uevent_seqnum); /* uevent helper program, used during early boo */ -static ssize_t uevent_helper_show(struct kset *kset, char *page) +static ssize_t uevent_helper_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { - return sprintf(page, "%s\n", uevent_helper); + return sprintf(buf, "%s\n", uevent_helper); } -static ssize_t uevent_helper_store(struct kset *kset, const char *page, size_t count) +static ssize_t uevent_helper_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) { if (count+1 > UEVENT_HELPER_PATH_LEN) return -ENOENT; - memcpy(uevent_helper, page, count); + memcpy(uevent_helper, buf, count); uevent_helper[count] = '\0'; if (count && uevent_helper[count-1] == '\n') uevent_helper[count-1] = '\0'; @@ -50,21 +54,24 @@ KERNEL_ATTR_RW(uevent_helper); #endif #ifdef CONFIG_KEXEC -static ssize_t kexec_loaded_show(struct kset *kset, char *page) +static ssize_t kexec_loaded_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { - return sprintf(page, "%d\n", !!kexec_image); + return sprintf(buf, "%d\n", !!kexec_image); } KERNEL_ATTR_RO(kexec_loaded); -static ssize_t kexec_crash_loaded_show(struct kset *kset, char *page) +static ssize_t kexec_crash_loaded_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { - return sprintf(page, "%d\n", !!kexec_crash_image); + return sprintf(buf, "%d\n", !!kexec_crash_image); } KERNEL_ATTR_RO(kexec_crash_loaded); -static ssize_t vmcoreinfo_show(struct kset *kset, char *page) +static ssize_t vmcoreinfo_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { - return sprintf(page, "%lx %x\n", + return sprintf(buf, "%lx %x\n", paddr_vmcoreinfo_note(), (unsigned int)vmcoreinfo_max_size); } @@ -94,8 +101,8 @@ static struct bin_attribute notes_attr = { .read = ¬es_read, }; -decl_subsys(kernel, NULL, NULL); -EXPORT_SYMBOL_GPL(kernel_subsys); +struct kobject *kernel_kobj; +EXPORT_SYMBOL_GPL(kernel_kobj); static struct attribute * kernel_attrs[] = { #if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET) @@ -116,24 +123,39 @@ static struct attribute_group kernel_attr_group = { static int __init ksysfs_init(void) { - int error = subsystem_register(&kernel_subsys); - if (!error) - error = sysfs_create_group(&kernel_subsys.kobj, - &kernel_attr_group); + int error; - if (!error && notes_size > 0) { - notes_attr.size = notes_size; - error = sysfs_create_bin_file(&kernel_subsys.kobj, - ¬es_attr); + kernel_kobj = kobject_create_and_add("kernel", NULL); + if (!kernel_kobj) { + error = -ENOMEM; + goto exit; } + error = sysfs_create_group(kernel_kobj, &kernel_attr_group); + if (error) + goto kset_exit; - /* - * Create "/sys/kernel/uids" directory and corresponding root user's - * directory under it. - */ - if (!error) - error = uids_kobject_init(); + if (notes_size > 0) { + notes_attr.size = notes_size; + error = sysfs_create_bin_file(kernel_kobj, ¬es_attr); + if (error) + goto group_exit; + } + /* create the /sys/kernel/uids/ directory */ + error = uids_sysfs_init(); + if (error) + goto notes_exit; + + return 0; + +notes_exit: + if (notes_size > 0) + sysfs_remove_bin_file(kernel_kobj, ¬es_attr); +group_exit: + sysfs_remove_group(kernel_kobj, &kernel_attr_group); +kset_exit: + kobject_put(kernel_kobj); +exit: return error; } diff --git a/kernel/module.c b/kernel/module.c index c2e3e2e98801df8c45bc91a49975e97a16619053..dcb8a2cbf75e2152496ebe4ca25d19ac50018401 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -47,8 +47,6 @@ #include <asm/cacheflush.h> #include <linux/license.h> -extern int module_sysfs_initialized; - #if 0 #define DEBUGP printk #else @@ -1122,7 +1120,7 @@ static void add_notes_attrs(struct module *mod, unsigned int nsect, ++loaded; } - notes_attrs->dir = kobject_add_dir(&mod->mkobj.kobj, "notes"); + notes_attrs->dir = kobject_create_and_add("notes", &mod->mkobj.kobj); if (!notes_attrs->dir) goto out; @@ -1219,15 +1217,16 @@ int mod_sysfs_init(struct module *mod) err = -EINVAL; goto out; } - memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj)); - err = kobject_set_name(&mod->mkobj.kobj, "%s", mod->name); - if (err) - goto out; - kobj_set_kset_s(&mod->mkobj, module_subsys); mod->mkobj.mod = mod; - kobject_init(&mod->mkobj.kobj); + memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj)); + mod->mkobj.kobj.kset = module_kset; + err = kobject_init_and_add(&mod->mkobj.kobj, &module_ktype, NULL, + "%s", mod->name); + if (err) + kobject_put(&mod->mkobj.kobj); + /* delay uevent until full sysfs population */ out: return err; } @@ -1238,12 +1237,7 @@ int mod_sysfs_setup(struct module *mod, { int err; - /* delay uevent until full sysfs population */ - err = kobject_add(&mod->mkobj.kobj); - if (err) - goto out; - - mod->holders_dir = kobject_add_dir(&mod->mkobj.kobj, "holders"); + mod->holders_dir = kobject_create_and_add("holders", &mod->mkobj.kobj); if (!mod->holders_dir) { err = -ENOMEM; goto out_unreg; @@ -1263,11 +1257,9 @@ int mod_sysfs_setup(struct module *mod, out_unreg_param: module_param_sysfs_remove(mod); out_unreg_holders: - kobject_unregister(mod->holders_dir); + kobject_put(mod->holders_dir); out_unreg: - kobject_del(&mod->mkobj.kobj); kobject_put(&mod->mkobj.kobj); -out: return err; } #endif @@ -1276,9 +1268,9 @@ static void mod_kobject_remove(struct module *mod) { module_remove_modinfo_attrs(mod); module_param_sysfs_remove(mod); - kobject_unregister(mod->mkobj.drivers_dir); - kobject_unregister(mod->holders_dir); - kobject_unregister(&mod->mkobj.kobj); + kobject_put(mod->mkobj.drivers_dir); + kobject_put(mod->holders_dir); + kobject_put(&mod->mkobj.kobj); } /* @@ -1884,10 +1876,10 @@ static struct module *load_module(void __user *umod, /* Now we've moved module, initialize linked lists, etc. */ module_unload_init(mod); - /* Initialize kobject, so we can reference it. */ + /* add kobject, so we can reference it. */ err = mod_sysfs_init(mod); if (err) - goto cleanup; + goto free_unload; /* Set up license info based on the info section */ set_license(mod, get_modinfo(sechdrs, infoindex, "license")); @@ -2057,6 +2049,9 @@ static struct module *load_module(void __user *umod, arch_cleanup: module_arch_cleanup(mod); cleanup: + kobject_del(&mod->mkobj.kobj); + kobject_put(&mod->mkobj.kobj); + free_unload: module_unload_free(mod); module_free(mod, mod->module_init); free_core: @@ -2502,93 +2497,6 @@ void print_modules(void) printk("\n"); } -#ifdef CONFIG_SYSFS -static char *make_driver_name(struct device_driver *drv) -{ - char *driver_name; - - driver_name = kmalloc(strlen(drv->name) + strlen(drv->bus->name) + 2, - GFP_KERNEL); - if (!driver_name) - return NULL; - - sprintf(driver_name, "%s:%s", drv->bus->name, drv->name); - return driver_name; -} - -static void module_create_drivers_dir(struct module_kobject *mk) -{ - if (!mk || mk->drivers_dir) - return; - - mk->drivers_dir = kobject_add_dir(&mk->kobj, "drivers"); -} - -void module_add_driver(struct module *mod, struct device_driver *drv) -{ - char *driver_name; - int no_warn; - struct module_kobject *mk = NULL; - - if (!drv) - return; - - if (mod) - mk = &mod->mkobj; - else if (drv->mod_name) { - struct kobject *mkobj; - - /* Lookup built-in module entry in /sys/modules */ - mkobj = kset_find_obj(&module_subsys, drv->mod_name); - if (mkobj) { - mk = container_of(mkobj, struct module_kobject, kobj); - /* remember our module structure */ - drv->mkobj = mk; - /* kset_find_obj took a reference */ - kobject_put(mkobj); - } - } - - if (!mk) - return; - - /* Don't check return codes; these calls are idempotent */ - no_warn = sysfs_create_link(&drv->kobj, &mk->kobj, "module"); - driver_name = make_driver_name(drv); - if (driver_name) { - module_create_drivers_dir(mk); - no_warn = sysfs_create_link(mk->drivers_dir, &drv->kobj, - driver_name); - kfree(driver_name); - } -} -EXPORT_SYMBOL(module_add_driver); - -void module_remove_driver(struct device_driver *drv) -{ - struct module_kobject *mk = NULL; - char *driver_name; - - if (!drv) - return; - - sysfs_remove_link(&drv->kobj, "module"); - - if (drv->owner) - mk = &drv->owner->mkobj; - else if (drv->mkobj) - mk = drv->mkobj; - if (mk && mk->drivers_dir) { - driver_name = make_driver_name(drv); - if (driver_name) { - sysfs_remove_link(mk->drivers_dir, driver_name); - kfree(driver_name); - } - } -} -EXPORT_SYMBOL(module_remove_driver); -#endif - #ifdef CONFIG_MODVERSIONS /* Generate the signature for struct module here, too, for modversions. */ void struct_module(struct module *mod) { return; } diff --git a/kernel/params.c b/kernel/params.c index 7686417ee00eba070b7d9b5c9dd293f9991199f1..b4da9505f4d21215fd6838427553441c0f09b03d 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -560,11 +560,10 @@ static void __init kernel_param_sysfs_setup(const char *name, BUG_ON(!mk); mk->mod = THIS_MODULE; - kobj_set_kset_s(mk, module_subsys); - kobject_set_name(&mk->kobj, name); - kobject_init(&mk->kobj); - ret = kobject_add(&mk->kobj); + mk->kobj.kset = module_kset; + ret = kobject_init_and_add(&mk->kobj, &module_ktype, NULL, "%s", name); if (ret) { + kobject_put(&mk->kobj); printk(KERN_ERR "Module '%s' failed to be added to sysfs, " "error number %d\n", name, ret); printk(KERN_ERR "The system will be unstable now.\n"); @@ -679,8 +678,6 @@ static struct sysfs_ops module_sysfs_ops = { .store = module_attr_store, }; -static struct kobj_type module_ktype; - static int uevent_filter(struct kset *kset, struct kobject *kobj) { struct kobj_type *ktype = get_ktype(kobj); @@ -694,21 +691,11 @@ static struct kset_uevent_ops module_uevent_ops = { .filter = uevent_filter, }; -decl_subsys(module, &module_ktype, &module_uevent_ops); +struct kset *module_kset; int module_sysfs_initialized; -static void module_release(struct kobject *kobj) -{ - /* - * Stupid empty release function to allow the memory for the kobject to - * be properly cleaned up. This will not need to be present for 2.6.25 - * with the upcoming kobject core rework. - */ -} - -static struct kobj_type module_ktype = { +struct kobj_type module_ktype = { .sysfs_ops = &module_sysfs_ops, - .release = module_release, }; /* @@ -716,13 +703,11 @@ static struct kobj_type module_ktype = { */ static int __init param_sysfs_init(void) { - int ret; - - ret = subsystem_register(&module_subsys); - if (ret < 0) { - printk(KERN_WARNING "%s (%d): subsystem_register error: %d\n", - __FILE__, __LINE__, ret); - return ret; + module_kset = kset_create_and_add("module", &module_uevent_ops, NULL); + if (!module_kset) { + printk(KERN_WARNING "%s (%d): error creating kset\n", + __FILE__, __LINE__); + return -ENOMEM; } module_sysfs_initialized = 1; @@ -732,14 +717,7 @@ static int __init param_sysfs_init(void) } subsys_initcall(param_sysfs_init); -#else -#if 0 -static struct sysfs_ops module_sysfs_ops = { - .show = NULL, - .store = NULL, -}; -#endif -#endif +#endif /* CONFIG_SYSFS */ EXPORT_SYMBOL(param_set_byte); EXPORT_SYMBOL(param_get_byte); diff --git a/kernel/power/disk.c b/kernel/power/disk.c index 05b64790fe8391ed5189eee02144e5cf63f3fa2b..b138b431e27135aa7b2716335288069ea00beeee 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c @@ -567,7 +567,8 @@ static const char * const hibernation_modes[] = { * supports it (as determined by having hibernation_ops). */ -static ssize_t disk_show(struct kset *kset, char *buf) +static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) { int i; char *start = buf; @@ -597,7 +598,8 @@ static ssize_t disk_show(struct kset *kset, char *buf) } -static ssize_t disk_store(struct kset *kset, const char *buf, size_t n) +static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t n) { int error = 0; int i; @@ -642,13 +644,15 @@ static ssize_t disk_store(struct kset *kset, const char *buf, size_t n) power_attr(disk); -static ssize_t resume_show(struct kset *kset, char *buf) +static ssize_t resume_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) { return sprintf(buf,"%d:%d\n", MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device)); } -static ssize_t resume_store(struct kset *kset, const char *buf, size_t n) +static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t n) { unsigned int maj, min; dev_t res; @@ -674,12 +678,14 @@ static ssize_t resume_store(struct kset *kset, const char *buf, size_t n) power_attr(resume); -static ssize_t image_size_show(struct kset *kset, char *buf) +static ssize_t image_size_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) { return sprintf(buf, "%lu\n", image_size); } -static ssize_t image_size_store(struct kset *kset, const char *buf, size_t n) +static ssize_t image_size_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t n) { unsigned long size; @@ -708,7 +714,7 @@ static struct attribute_group attr_group = { static int __init pm_disk_init(void) { - return sysfs_create_group(&power_subsys.kobj, &attr_group); + return sysfs_create_group(power_kobj, &attr_group); } core_initcall(pm_disk_init); diff --git a/kernel/power/main.c b/kernel/power/main.c index f71c9504a5c5edd9a91b617ba9595e9c40e1ff1d..efc08360e627199374837ed95ea31ebcd0f94a80 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -276,8 +276,7 @@ EXPORT_SYMBOL(pm_suspend); #endif /* CONFIG_SUSPEND */ -decl_subsys(power,NULL,NULL); - +struct kobject *power_kobj; /** * state - control system power state. @@ -290,7 +289,8 @@ decl_subsys(power,NULL,NULL); * proper enumerated value, and initiates a suspend transition. */ -static ssize_t state_show(struct kset *kset, char *buf) +static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) { char *s = buf; #ifdef CONFIG_SUSPEND @@ -311,7 +311,8 @@ static ssize_t state_show(struct kset *kset, char *buf) return (s - buf); } -static ssize_t state_store(struct kset *kset, const char *buf, size_t n) +static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t n) { #ifdef CONFIG_SUSPEND suspend_state_t state = PM_SUSPEND_STANDBY; @@ -348,13 +349,15 @@ power_attr(state); #ifdef CONFIG_PM_TRACE int pm_trace_enabled; -static ssize_t pm_trace_show(struct kset *kset, char *buf) +static ssize_t pm_trace_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) { return sprintf(buf, "%d\n", pm_trace_enabled); } static ssize_t -pm_trace_store(struct kset *kset, const char *buf, size_t n) +pm_trace_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t n) { int val; @@ -386,10 +389,10 @@ static struct attribute_group attr_group = { static int __init pm_init(void) { - int error = subsystem_register(&power_subsys); - if (!error) - error = sysfs_create_group(&power_subsys.kobj,&attr_group); - return error; + power_kobj = kobject_create_and_add("power", NULL); + if (!power_kobj) + return -ENOMEM; + return sysfs_create_group(power_kobj, &attr_group); } core_initcall(pm_init); diff --git a/kernel/power/power.h b/kernel/power/power.h index 195dc4611764b08a65780976a6231aaf004889fe..2093c3a9a994d8a7a3bd82487200b925ee16ac61 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -54,7 +54,7 @@ extern int pfn_is_nosave(unsigned long); extern struct mutex pm_mutex; #define power_attr(_name) \ -static struct subsys_attribute _name##_attr = { \ +static struct kobj_attribute _name##_attr = { \ .attr = { \ .name = __stringify(_name), \ .mode = 0644, \ @@ -63,8 +63,6 @@ static struct subsys_attribute _name##_attr = { \ .store = _name##_store, \ } -extern struct kset power_subsys; - /* Preferred image size in bytes (default 500 MB) */ extern unsigned long image_size; extern int in_suspend; diff --git a/kernel/rtmutex-tester.c b/kernel/rtmutex-tester.c index e3055ba6915978c4290492ef16cacb3f3a844c61..092e4c620af908410a30ef3ee9ece43df72dcb84 100644 --- a/kernel/rtmutex-tester.c +++ b/kernel/rtmutex-tester.c @@ -394,7 +394,7 @@ static SYSDEV_ATTR(status, 0600, sysfs_test_status, NULL); static SYSDEV_ATTR(command, 0600, NULL, sysfs_test_command); static struct sysdev_class rttest_sysclass = { - set_kset_name("rttest"), + .name = "rttest", }; static int init_test_thread(int id) diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index c8a9d13874dfdcf85c6b2ab9d7d03f92a8f39401..8d6125ad2cf0cf3c76368e582d9750066d176232 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -441,7 +441,7 @@ static SYSDEV_ATTR(available_clocksource, 0600, sysfs_show_available_clocksources, NULL); static struct sysdev_class clocksource_sysclass = { - set_kset_name("clocksource"), + .name = "clocksource", }; static struct sys_device device_clocksource = { diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index e5e466b2759893ccd21cea1e2242b8fbf7dac9a5..ab46ae8c062b0b971aaae2fc28071d0cc01260ed 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -335,9 +335,9 @@ static int timekeeping_suspend(struct sys_device *dev, pm_message_t state) /* sysfs resume/suspend bits for timekeeping */ static struct sysdev_class timekeeping_sysclass = { + .name = "timekeeping", .resume = timekeeping_resume, .suspend = timekeeping_suspend, - set_kset_name("timekeeping"), }; static struct sys_device device_timer = { diff --git a/kernel/user.c b/kernel/user.c index 8320a87f3e5a11f11e2159488cf2dc3f6d9371d3..ab4fd706993b1e22dccae4d3fafcf0cf0f48fbb3 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -115,7 +115,7 @@ static void sched_switch_user(struct task_struct *p) { } #if defined(CONFIG_FAIR_USER_SCHED) && defined(CONFIG_SYSFS) -static struct kobject uids_kobject; /* represents /sys/kernel/uids directory */ +static struct kset *uids_kset; /* represents the /sys/kernel/uids/ directory */ static DEFINE_MUTEX(uids_mutex); static inline void uids_mutex_lock(void) @@ -128,86 +128,83 @@ static inline void uids_mutex_unlock(void) mutex_unlock(&uids_mutex); } -/* return cpu shares held by the user */ -static ssize_t cpu_shares_show(struct kset *kset, char *buffer) +/* uid directory attributes */ +static ssize_t cpu_shares_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) { - struct user_struct *up = container_of(kset, struct user_struct, kset); + struct user_struct *up = container_of(kobj, struct user_struct, kobj); - return sprintf(buffer, "%lu\n", sched_group_shares(up->tg)); + return sprintf(buf, "%lu\n", sched_group_shares(up->tg)); } -/* modify cpu shares held by the user */ -static ssize_t cpu_shares_store(struct kset *kset, const char *buffer, - size_t size) +static ssize_t cpu_shares_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t size) { - struct user_struct *up = container_of(kset, struct user_struct, kset); + struct user_struct *up = container_of(kobj, struct user_struct, kobj); unsigned long shares; int rc; - sscanf(buffer, "%lu", &shares); + sscanf(buf, "%lu", &shares); rc = sched_group_set_shares(up->tg, shares); return (rc ? rc : size); } -static void user_attr_init(struct subsys_attribute *sa, char *name, int mode) +static struct kobj_attribute cpu_share_attr = + __ATTR(cpu_share, 0644, cpu_shares_show, cpu_shares_store); + +/* default attributes per uid directory */ +static struct attribute *uids_attributes[] = { + &cpu_share_attr.attr, + NULL +}; + +/* the lifetime of user_struct is not managed by the core (now) */ +static void uids_release(struct kobject *kobj) { - sa->attr.name = name; - sa->attr.mode = mode; - sa->show = cpu_shares_show; - sa->store = cpu_shares_store; + return; } -/* Create "/sys/kernel/uids/<uid>" directory and - * "/sys/kernel/uids/<uid>/cpu_share" file for this user. - */ -static int user_kobject_create(struct user_struct *up) +static struct kobj_type uids_ktype = { + .sysfs_ops = &kobj_sysfs_ops, + .default_attrs = uids_attributes, + .release = uids_release, +}; + +/* create /sys/kernel/uids/<uid>/cpu_share file for this user */ +static int uids_user_create(struct user_struct *up) { - struct kset *kset = &up->kset; - struct kobject *kobj = &kset->kobj; + struct kobject *kobj = &up->kobj; int error; - memset(kset, 0, sizeof(struct kset)); - kobj->parent = &uids_kobject; /* create under /sys/kernel/uids dir */ - kobject_set_name(kobj, "%d", up->uid); - kset_init(kset); - user_attr_init(&up->user_attr, "cpu_share", 0644); - - error = kobject_add(kobj); - if (error) + memset(kobj, 0, sizeof(struct kobject)); + kobj->kset = uids_kset; + error = kobject_init_and_add(kobj, &uids_ktype, NULL, "%d", up->uid); + if (error) { + kobject_put(kobj); goto done; - - error = sysfs_create_file(kobj, &up->user_attr.attr); - if (error) - kobject_del(kobj); + } kobject_uevent(kobj, KOBJ_ADD); - done: return error; } -/* create these in sysfs filesystem: +/* create these entries in sysfs: * "/sys/kernel/uids" directory * "/sys/kernel/uids/0" directory (for root user) * "/sys/kernel/uids/0/cpu_share" file (for root user) */ -int __init uids_kobject_init(void) +int __init uids_sysfs_init(void) { - int error; + uids_kset = kset_create_and_add("uids", NULL, kernel_kobj); + if (!uids_kset) + return -ENOMEM; - /* create under /sys/kernel dir */ - uids_kobject.parent = &kernel_subsys.kobj; - uids_kobject.kset = &kernel_subsys; - kobject_set_name(&uids_kobject, "uids"); - kobject_init(&uids_kobject); - - error = kobject_add(&uids_kobject); - if (!error) - error = user_kobject_create(&root_user); - - return error; + return uids_user_create(&root_user); } /* work function to remove sysfs directory for a user and free up @@ -216,7 +213,6 @@ int __init uids_kobject_init(void) static void remove_user_sysfs_dir(struct work_struct *w) { struct user_struct *up = container_of(w, struct user_struct, work); - struct kobject *kobj = &up->kset.kobj; unsigned long flags; int remove_user = 0; @@ -238,9 +234,9 @@ static void remove_user_sysfs_dir(struct work_struct *w) if (!remove_user) goto done; - sysfs_remove_file(kobj, &up->user_attr.attr); - kobject_uevent(kobj, KOBJ_REMOVE); - kobject_del(kobj); + kobject_uevent(&up->kobj, KOBJ_REMOVE); + kobject_del(&up->kobj); + kobject_put(&up->kobj); sched_destroy_user(up); key_put(up->uid_keyring); @@ -267,7 +263,8 @@ static inline void free_user(struct user_struct *up, unsigned long flags) #else /* CONFIG_FAIR_USER_SCHED && CONFIG_SYSFS */ -static inline int user_kobject_create(struct user_struct *up) { return 0; } +int uids_sysfs_init(void) { return 0; } +static inline int uids_user_create(struct user_struct *up) { return 0; } static inline void uids_mutex_lock(void) { } static inline void uids_mutex_unlock(void) { } @@ -324,7 +321,7 @@ struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid) struct hlist_head *hashent = uidhashentry(ns, uid); struct user_struct *up; - /* Make uid_hash_find() + user_kobject_create() + uid_hash_insert() + /* Make uid_hash_find() + uids_user_create() + uid_hash_insert() * atomic. */ uids_mutex_lock(); @@ -370,7 +367,7 @@ struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid) return NULL; } - if (user_kobject_create(new)) { + if (uids_user_create(new)) { sched_destroy_user(new); key_put(new->uid_keyring); key_put(new->session_keyring); diff --git a/lib/kobject.c b/lib/kobject.c index 3590f022a609cf7828c259b9485503fd3cda9683..1d63ead1815e4f5cb8aae5ea2d86a1541eed23a2 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -18,58 +18,57 @@ #include <linux/stat.h> #include <linux/slab.h> -/** - * populate_dir - populate directory with attributes. - * @kobj: object we're working on. - * - * Most subsystems have a set of default attributes that - * are associated with an object that registers with them. - * This is a helper called during object registration that - * loops through the default attributes of the subsystem - * and creates attributes files for them in sysfs. +/* + * populate_dir - populate directory with attributes. + * @kobj: object we're working on. * + * Most subsystems have a set of default attributes that are associated + * with an object that registers with them. This is a helper called during + * object registration that loops through the default attributes of the + * subsystem and creates attributes files for them in sysfs. */ - -static int populate_dir(struct kobject * kobj) +static int populate_dir(struct kobject *kobj) { - struct kobj_type * t = get_ktype(kobj); - struct attribute * attr; + struct kobj_type *t = get_ktype(kobj); + struct attribute *attr; int error = 0; int i; - + if (t && t->default_attrs) { for (i = 0; (attr = t->default_attrs[i]) != NULL; i++) { - if ((error = sysfs_create_file(kobj,attr))) + error = sysfs_create_file(kobj, attr); + if (error) break; } } return error; } -static int create_dir(struct kobject * kobj) +static int create_dir(struct kobject *kobj) { int error = 0; if (kobject_name(kobj)) { error = sysfs_create_dir(kobj); if (!error) { - if ((error = populate_dir(kobj))) + error = populate_dir(kobj); + if (error) sysfs_remove_dir(kobj); } } return error; } -static inline struct kobject * to_kobj(struct list_head * entry) +static inline struct kobject *to_kobj(struct list_head *entry) { - return container_of(entry,struct kobject,entry); + return container_of(entry, struct kobject, entry); } static int get_kobj_path_length(struct kobject *kobj) { int length = 1; - struct kobject * parent = kobj; + struct kobject *parent = kobj; - /* walk up the ancestors until we hit the one pointing to the + /* walk up the ancestors until we hit the one pointing to the * root. * Add 1 to strlen for leading '/' of each level. */ @@ -84,18 +83,19 @@ static int get_kobj_path_length(struct kobject *kobj) static void fill_kobj_path(struct kobject *kobj, char *path, int length) { - struct kobject * parent; + struct kobject *parent; --length; for (parent = kobj; parent; parent = parent->parent) { int cur = strlen(kobject_name(parent)); /* back up enough to print this name with '/' */ length -= cur; - strncpy (path + length, kobject_name(parent), cur); + strncpy(path + length, kobject_name(parent), cur); *(path + --length) = '/'; } - pr_debug("%s: path = '%s'\n",__FUNCTION__,path); + pr_debug("kobject: '%s' (%p): %s: path = '%s'\n", kobject_name(kobj), + kobj, __FUNCTION__, path); } /** @@ -123,179 +123,286 @@ char *kobject_get_path(struct kobject *kobj, gfp_t gfp_mask) } EXPORT_SYMBOL_GPL(kobject_get_path); -/** - * kobject_init - initialize object. - * @kobj: object in question. - */ -void kobject_init(struct kobject * kobj) +/* add the kobject to its kset's list */ +static void kobj_kset_join(struct kobject *kobj) { - if (!kobj) + if (!kobj->kset) return; - kref_init(&kobj->kref); - INIT_LIST_HEAD(&kobj->entry); - kobj->kset = kset_get(kobj->kset); + + kset_get(kobj->kset); + spin_lock(&kobj->kset->list_lock); + list_add_tail(&kobj->entry, &kobj->kset->list); + spin_unlock(&kobj->kset->list_lock); } +/* remove the kobject from its kset's list */ +static void kobj_kset_leave(struct kobject *kobj) +{ + if (!kobj->kset) + return; -/** - * unlink - remove kobject from kset list. - * @kobj: kobject. - * - * Remove the kobject from the kset list and decrement - * its parent's refcount. - * This is separated out, so we can use it in both - * kobject_del() and kobject_add() on error. - */ + spin_lock(&kobj->kset->list_lock); + list_del_init(&kobj->entry); + spin_unlock(&kobj->kset->list_lock); + kset_put(kobj->kset); +} -static void unlink(struct kobject * kobj) +static void kobject_init_internal(struct kobject *kobj) { - if (kobj->kset) { - spin_lock(&kobj->kset->list_lock); - list_del_init(&kobj->entry); - spin_unlock(&kobj->kset->list_lock); - } - kobject_put(kobj); + if (!kobj) + return; + kref_init(&kobj->kref); + INIT_LIST_HEAD(&kobj->entry); } -/** - * kobject_add - add an object to the hierarchy. - * @kobj: object. - */ -int kobject_add(struct kobject * kobj) +static int kobject_add_internal(struct kobject *kobj) { int error = 0; - struct kobject * parent; + struct kobject *parent; - if (!(kobj = kobject_get(kobj))) + if (!kobj) return -ENOENT; - if (!kobj->k_name) - kobject_set_name(kobj, "NO_NAME"); - if (!*kobj->k_name) { - pr_debug("kobject attempted to be registered with no name!\n"); + + if (!kobj->name || !kobj->name[0]) { + pr_debug("kobject: (%p): attempted to be registered with empty " + "name!\n", kobj); WARN_ON(1); - kobject_put(kobj); return -EINVAL; } - parent = kobject_get(kobj->parent); - pr_debug("kobject %s: registering. parent: %s, set: %s\n", - kobject_name(kobj), parent ? kobject_name(parent) : "<NULL>", - kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>" ); + parent = kobject_get(kobj->parent); + /* join kset if set, use it as parent if we do not already have one */ if (kobj->kset) { - spin_lock(&kobj->kset->list_lock); - if (!parent) parent = kobject_get(&kobj->kset->kobj); - - list_add_tail(&kobj->entry,&kobj->kset->list); - spin_unlock(&kobj->kset->list_lock); + kobj_kset_join(kobj); kobj->parent = parent; } + pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n", + kobject_name(kobj), kobj, __FUNCTION__, + parent ? kobject_name(parent) : "<NULL>", + kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>"); + error = create_dir(kobj); if (error) { - /* unlink does the kobject_put() for us */ - unlink(kobj); + kobj_kset_leave(kobj); kobject_put(parent); + kobj->parent = NULL; /* be noisy on error issues */ if (error == -EEXIST) - printk(KERN_ERR "kobject_add failed for %s with " + printk(KERN_ERR "%s failed for %s with " "-EEXIST, don't try to register things with " "the same name in the same directory.\n", - kobject_name(kobj)); + __FUNCTION__, kobject_name(kobj)); else - printk(KERN_ERR "kobject_add failed for %s (%d)\n", - kobject_name(kobj), error); + printk(KERN_ERR "%s failed for %s (%d)\n", + __FUNCTION__, kobject_name(kobj), error); dump_stack(); - } + } else + kobj->state_in_sysfs = 1; return error; } /** - * kobject_register - initialize and add an object. - * @kobj: object in question. + * kobject_set_name_vargs - Set the name of an kobject + * @kobj: struct kobject to set the name of + * @fmt: format string used to build the name + * @vargs: vargs to format the string. */ - -int kobject_register(struct kobject * kobj) +static int kobject_set_name_vargs(struct kobject *kobj, const char *fmt, + va_list vargs) { - int error = -EINVAL; - if (kobj) { - kobject_init(kobj); - error = kobject_add(kobj); - if (!error) - kobject_uevent(kobj, KOBJ_ADD); - } - return error; -} + va_list aq; + char *name; + + va_copy(aq, vargs); + name = kvasprintf(GFP_KERNEL, fmt, vargs); + va_end(aq); + if (!name) + return -ENOMEM; + + /* Free the old name, if necessary. */ + kfree(kobj->name); + + /* Now, set the new name */ + kobj->name = name; + + return 0; +} /** * kobject_set_name - Set the name of a kobject - * @kobj: kobject to name + * @kobj: struct kobject to set the name of * @fmt: format string used to build the name * * This sets the name of the kobject. If you have already added the * kobject to the system, you must call kobject_rename() in order to * change the name of the kobject. */ -int kobject_set_name(struct kobject * kobj, const char * fmt, ...) +int kobject_set_name(struct kobject *kobj, const char *fmt, ...) { - int error = 0; - int limit; - int need; va_list args; - char *name; + int retval; - /* find out how big a buffer we need */ - name = kmalloc(1024, GFP_KERNEL); - if (!name) { - error = -ENOMEM; - goto done; - } va_start(args, fmt); - need = vsnprintf(name, 1024, fmt, args); + retval = kobject_set_name_vargs(kobj, fmt, args); va_end(args); - kfree(name); - /* Allocate the new space and copy the string in */ - limit = need + 1; - name = kmalloc(limit, GFP_KERNEL); - if (!name) { - error = -ENOMEM; - goto done; + return retval; +} +EXPORT_SYMBOL(kobject_set_name); + +/** + * kobject_init - initialize a kobject structure + * @kobj: pointer to the kobject to initialize + * @ktype: pointer to the ktype for this kobject. + * + * This function will properly initialize a kobject such that it can then + * be passed to the kobject_add() call. + * + * After this function is called, the kobject MUST be cleaned up by a call + * to kobject_put(), not by a call to kfree directly to ensure that all of + * the memory is cleaned up properly. + */ +void kobject_init(struct kobject *kobj, struct kobj_type *ktype) +{ + char *err_str; + + if (!kobj) { + err_str = "invalid kobject pointer!"; + goto error; + } + if (!ktype) { + err_str = "must have a ktype to be initialized properly!\n"; + goto error; + } + if (kobj->state_initialized) { + /* do not error out as sometimes we can recover */ + printk(KERN_ERR "kobject (%p): tried to init an initialized " + "object, something is seriously wrong.\n", kobj); + dump_stack(); } - va_start(args, fmt); - need = vsnprintf(name, limit, fmt, args); - va_end(args); - /* something wrong with the string we copied? */ - if (need >= limit) { - kfree(name); - error = -EFAULT; - goto done; + kref_init(&kobj->kref); + INIT_LIST_HEAD(&kobj->entry); + kobj->ktype = ktype; + kobj->state_in_sysfs = 0; + kobj->state_add_uevent_sent = 0; + kobj->state_remove_uevent_sent = 0; + kobj->state_initialized = 1; + return; + +error: + printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str); + dump_stack(); +} +EXPORT_SYMBOL(kobject_init); + +static int kobject_add_varg(struct kobject *kobj, struct kobject *parent, + const char *fmt, va_list vargs) +{ + va_list aq; + int retval; + + va_copy(aq, vargs); + retval = kobject_set_name_vargs(kobj, fmt, aq); + va_end(aq); + if (retval) { + printk(KERN_ERR "kobject: can not set name properly!\n"); + return retval; } + kobj->parent = parent; + return kobject_add_internal(kobj); +} - /* Free the old name, if necessary. */ - kfree(kobj->k_name); +/** + * kobject_add - the main kobject add function + * @kobj: the kobject to add + * @parent: pointer to the parent of the kobject. + * @fmt: format to name the kobject with. + * + * The kobject name is set and added to the kobject hierarchy in this + * function. + * + * If @parent is set, then the parent of the @kobj will be set to it. + * If @parent is NULL, then the parent of the @kobj will be set to the + * kobject associted with the kset assigned to this kobject. If no kset + * is assigned to the kobject, then the kobject will be located in the + * root of the sysfs tree. + * + * If this function returns an error, kobject_put() must be called to + * properly clean up the memory associated with the object. + * Under no instance should the kobject that is passed to this function + * be directly freed with a call to kfree(), that can leak memory. + * + * Note, no "add" uevent will be created with this call, the caller should set + * up all of the necessary sysfs files for the object and then call + * kobject_uevent() with the UEVENT_ADD parameter to ensure that + * userspace is properly notified of this kobject's creation. + */ +int kobject_add(struct kobject *kobj, struct kobject *parent, + const char *fmt, ...) +{ + va_list args; + int retval; - /* Now, set the new name */ - kobj->k_name = name; -done: - return error; + if (!kobj) + return -EINVAL; + + if (!kobj->state_initialized) { + printk(KERN_ERR "kobject '%s' (%p): tried to add an " + "uninitialized object, something is seriously wrong.\n", + kobject_name(kobj), kobj); + dump_stack(); + return -EINVAL; + } + va_start(args, fmt); + retval = kobject_add_varg(kobj, parent, fmt, args); + va_end(args); + + return retval; } -EXPORT_SYMBOL(kobject_set_name); +EXPORT_SYMBOL(kobject_add); /** - * kobject_rename - change the name of an object - * @kobj: object in question. - * @new_name: object's new name + * kobject_init_and_add - initialize a kobject structure and add it to the kobject hierarchy + * @kobj: pointer to the kobject to initialize + * @ktype: pointer to the ktype for this kobject. + * @parent: pointer to the parent of this kobject. + * @fmt: the name of the kobject. + * + * This function combines the call to kobject_init() and + * kobject_add(). The same type of error handling after a call to + * kobject_add() and kobject lifetime rules are the same here. */ +int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype, + struct kobject *parent, const char *fmt, ...) +{ + va_list args; + int retval; + + kobject_init(kobj, ktype); + + va_start(args, fmt); + retval = kobject_add_varg(kobj, parent, fmt, args); + va_end(args); + + return retval; +} +EXPORT_SYMBOL_GPL(kobject_init_and_add); -int kobject_rename(struct kobject * kobj, const char *new_name) +/** + * kobject_rename - change the name of an object + * @kobj: object in question. + * @new_name: object's new name + */ +int kobject_rename(struct kobject *kobj, const char *new_name) { int error = 0; const char *devpath = NULL; @@ -334,8 +441,6 @@ int kobject_rename(struct kobject * kobj, const char *new_name) sprintf(devpath_string, "DEVPATH_OLD=%s", devpath); envp[0] = devpath_string; envp[1] = NULL; - /* Note : if we want to send the new name alone, not the full path, - * we could probably use kobject_name(kobj); */ error = sysfs_rename_dir(kobj, new_name); @@ -354,11 +459,10 @@ int kobject_rename(struct kobject * kobj, const char *new_name) } /** - * kobject_move - move object to another parent - * @kobj: object in question. - * @new_parent: object's new parent (can be NULL) + * kobject_move - move object to another parent + * @kobj: object in question. + * @new_parent: object's new parent (can be NULL) */ - int kobject_move(struct kobject *kobj, struct kobject *new_parent) { int error; @@ -406,68 +510,74 @@ int kobject_move(struct kobject *kobj, struct kobject *new_parent) } /** - * kobject_del - unlink kobject from hierarchy. - * @kobj: object. + * kobject_del - unlink kobject from hierarchy. + * @kobj: object. */ - -void kobject_del(struct kobject * kobj) +void kobject_del(struct kobject *kobj) { if (!kobj) return; - sysfs_remove_dir(kobj); - unlink(kobj); -} -/** - * kobject_unregister - remove object from hierarchy and decrement refcount. - * @kobj: object going away. - */ - -void kobject_unregister(struct kobject * kobj) -{ - if (!kobj) - return; - pr_debug("kobject %s: unregistering\n",kobject_name(kobj)); - kobject_uevent(kobj, KOBJ_REMOVE); - kobject_del(kobj); - kobject_put(kobj); + sysfs_remove_dir(kobj); + kobj->state_in_sysfs = 0; + kobj_kset_leave(kobj); + kobject_put(kobj->parent); + kobj->parent = NULL; } /** - * kobject_get - increment refcount for object. - * @kobj: object. + * kobject_get - increment refcount for object. + * @kobj: object. */ - -struct kobject * kobject_get(struct kobject * kobj) +struct kobject *kobject_get(struct kobject *kobj) { if (kobj) kref_get(&kobj->kref); return kobj; } -/** - * kobject_cleanup - free kobject resources. - * @kobj: object. +/* + * kobject_cleanup - free kobject resources. + * @kobj: object to cleanup */ - -void kobject_cleanup(struct kobject * kobj) +static void kobject_cleanup(struct kobject *kobj) { - struct kobj_type * t = get_ktype(kobj); - struct kset * s = kobj->kset; - struct kobject * parent = kobj->parent; - const char *name = kobj->k_name; + struct kobj_type *t = get_ktype(kobj); + const char *name = kobj->name; + + pr_debug("kobject: '%s' (%p): %s\n", + kobject_name(kobj), kobj, __FUNCTION__); + + if (t && !t->release) + pr_debug("kobject: '%s' (%p): does not have a release() " + "function, it is broken and must be fixed.\n", + kobject_name(kobj), kobj); + + /* send "remove" if the caller did not do it but sent "add" */ + if (kobj->state_add_uevent_sent && !kobj->state_remove_uevent_sent) { + pr_debug("kobject: '%s' (%p): auto cleanup 'remove' event\n", + kobject_name(kobj), kobj); + kobject_uevent(kobj, KOBJ_REMOVE); + } + + /* remove from sysfs if the caller did not do it */ + if (kobj->state_in_sysfs) { + pr_debug("kobject: '%s' (%p): auto cleanup kobject_del\n", + kobject_name(kobj), kobj); + kobject_del(kobj); + } - pr_debug("kobject %s: cleaning up\n",kobject_name(kobj)); if (t && t->release) { + pr_debug("kobject: '%s' (%p): calling ktype release\n", + kobject_name(kobj), kobj); t->release(kobj); - /* If we have a release function, we can guess that this was - * not a statically allocated kobject, so we should be safe to - * free the name */ + } + + /* free name if we allocated it */ + if (name) { + pr_debug("kobject: '%s': free name\n", name); kfree(name); } - if (s) - kset_put(s); - kobject_put(parent); } static void kobject_release(struct kref *kref) @@ -476,107 +586,130 @@ static void kobject_release(struct kref *kref) } /** - * kobject_put - decrement refcount for object. - * @kobj: object. + * kobject_put - decrement refcount for object. + * @kobj: object. * - * Decrement the refcount, and if 0, call kobject_cleanup(). + * Decrement the refcount, and if 0, call kobject_cleanup(). */ -void kobject_put(struct kobject * kobj) +void kobject_put(struct kobject *kobj) { if (kobj) kref_put(&kobj->kref, kobject_release); } - -static void dir_release(struct kobject *kobj) +static void dynamic_kobj_release(struct kobject *kobj) { + pr_debug("kobject: (%p): %s\n", kobj, __FUNCTION__); kfree(kobj); } -static struct kobj_type dir_ktype = { - .release = dir_release, - .sysfs_ops = NULL, - .default_attrs = NULL, +static struct kobj_type dynamic_kobj_ktype = { + .release = dynamic_kobj_release, + .sysfs_ops = &kobj_sysfs_ops, }; /** - * kobject_kset_add_dir - add sub directory of object. - * @kset: kset the directory is belongs to. - * @parent: object in which a directory is created. - * @name: directory name. + * kobject_create - create a struct kobject dynamically * - * Add a plain directory object as child of given object. + * This function creates a kobject structure dynamically and sets it up + * to be a "dynamic" kobject with a default release function set up. + * + * If the kobject was not able to be created, NULL will be returned. + * The kobject structure returned from here must be cleaned up with a + * call to kobject_put() and not kfree(), as kobject_init() has + * already been called on this structure. */ -struct kobject *kobject_kset_add_dir(struct kset *kset, - struct kobject *parent, const char *name) +struct kobject *kobject_create(void) { - struct kobject *k; - int ret; - - if (!parent) - return NULL; - - k = kzalloc(sizeof(*k), GFP_KERNEL); - if (!k) - return NULL; + struct kobject *kobj; - k->kset = kset; - k->parent = parent; - k->ktype = &dir_ktype; - kobject_set_name(k, name); - ret = kobject_register(k); - if (ret < 0) { - printk(KERN_WARNING "%s: kobject_register error: %d\n", - __func__, ret); - kobject_del(k); + kobj = kzalloc(sizeof(*kobj), GFP_KERNEL); + if (!kobj) return NULL; - } - return k; + kobject_init(kobj, &dynamic_kobj_ktype); + return kobj; } /** - * kobject_add_dir - add sub directory of object. - * @parent: object in which a directory is created. - * @name: directory name. + * kobject_create_and_add - create a struct kobject dynamically and register it with sysfs + * + * @name: the name for the kset + * @parent: the parent kobject of this kobject, if any. + * + * This function creates a kset structure dynamically and registers it + * with sysfs. When you are finished with this structure, call + * kobject_put() and the structure will be dynamically freed when + * it is no longer being used. * - * Add a plain directory object as child of given object. + * If the kobject was not able to be created, NULL will be returned. */ -struct kobject *kobject_add_dir(struct kobject *parent, const char *name) +struct kobject *kobject_create_and_add(const char *name, struct kobject *parent) { - return kobject_kset_add_dir(NULL, parent, name); + struct kobject *kobj; + int retval; + + kobj = kobject_create(); + if (!kobj) + return NULL; + + retval = kobject_add(kobj, parent, "%s", name); + if (retval) { + printk(KERN_WARNING "%s: kobject_add error: %d\n", + __FUNCTION__, retval); + kobject_put(kobj); + kobj = NULL; + } + return kobj; } +EXPORT_SYMBOL_GPL(kobject_create_and_add); /** - * kset_init - initialize a kset for use - * @k: kset + * kset_init - initialize a kset for use + * @k: kset */ - -void kset_init(struct kset * k) +void kset_init(struct kset *k) { - kobject_init(&k->kobj); + kobject_init_internal(&k->kobj); INIT_LIST_HEAD(&k->list); spin_lock_init(&k->list_lock); } +/* default kobject attribute operations */ +static ssize_t kobj_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct kobj_attribute *kattr; + ssize_t ret = -EIO; -/** - * kset_add - add a kset object to the hierarchy. - * @k: kset. - */ + kattr = container_of(attr, struct kobj_attribute, attr); + if (kattr->show) + ret = kattr->show(kobj, kattr, buf); + return ret; +} -int kset_add(struct kset * k) +static ssize_t kobj_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) { - return kobject_add(&k->kobj); + struct kobj_attribute *kattr; + ssize_t ret = -EIO; + + kattr = container_of(attr, struct kobj_attribute, attr); + if (kattr->store) + ret = kattr->store(kobj, kattr, buf, count); + return ret; } +struct sysfs_ops kobj_sysfs_ops = { + .show = kobj_attr_show, + .store = kobj_attr_store, +}; /** - * kset_register - initialize and add a kset. - * @k: kset. + * kset_register - initialize and add a kset. + * @k: kset. */ - -int kset_register(struct kset * k) +int kset_register(struct kset *k) { int err; @@ -584,46 +717,42 @@ int kset_register(struct kset * k) return -EINVAL; kset_init(k); - err = kset_add(k); + err = kobject_add_internal(&k->kobj); if (err) return err; kobject_uevent(&k->kobj, KOBJ_ADD); return 0; } - /** - * kset_unregister - remove a kset. - * @k: kset. + * kset_unregister - remove a kset. + * @k: kset. */ - -void kset_unregister(struct kset * k) +void kset_unregister(struct kset *k) { if (!k) return; - kobject_unregister(&k->kobj); + kobject_put(&k->kobj); } - /** - * kset_find_obj - search for object in kset. - * @kset: kset we're looking in. - * @name: object's name. + * kset_find_obj - search for object in kset. + * @kset: kset we're looking in. + * @name: object's name. * - * Lock kset via @kset->subsys, and iterate over @kset->list, - * looking for a matching kobject. If matching object is found - * take a reference and return the object. + * Lock kset via @kset->subsys, and iterate over @kset->list, + * looking for a matching kobject. If matching object is found + * take a reference and return the object. */ - -struct kobject * kset_find_obj(struct kset * kset, const char * name) +struct kobject *kset_find_obj(struct kset *kset, const char *name) { - struct list_head * entry; - struct kobject * ret = NULL; + struct list_head *entry; + struct kobject *ret = NULL; spin_lock(&kset->list_lock); - list_for_each(entry,&kset->list) { - struct kobject * k = to_kobj(entry); - if (kobject_name(k) && !strcmp(kobject_name(k),name)) { + list_for_each(entry, &kset->list) { + struct kobject *k = to_kobj(entry); + if (kobject_name(k) && !strcmp(kobject_name(k), name)) { ret = kobject_get(k); break; } @@ -632,47 +761,94 @@ struct kobject * kset_find_obj(struct kset * kset, const char * name) return ret; } -int subsystem_register(struct kset *s) +static void kset_release(struct kobject *kobj) { - return kset_register(s); + struct kset *kset = container_of(kobj, struct kset, kobj); + pr_debug("kobject: '%s' (%p): %s\n", + kobject_name(kobj), kobj, __FUNCTION__); + kfree(kset); } -void subsystem_unregister(struct kset *s) +static struct kobj_type kset_ktype = { + .sysfs_ops = &kobj_sysfs_ops, + .release = kset_release, +}; + +/** + * kset_create - create a struct kset dynamically + * + * @name: the name for the kset + * @uevent_ops: a struct kset_uevent_ops for the kset + * @parent_kobj: the parent kobject of this kset, if any. + * + * This function creates a kset structure dynamically. This structure can + * then be registered with the system and show up in sysfs with a call to + * kset_register(). When you are finished with this structure, if + * kset_register() has been called, call kset_unregister() and the + * structure will be dynamically freed when it is no longer being used. + * + * If the kset was not able to be created, NULL will be returned. + */ +static struct kset *kset_create(const char *name, + struct kset_uevent_ops *uevent_ops, + struct kobject *parent_kobj) { - kset_unregister(s); + struct kset *kset; + + kset = kzalloc(sizeof(*kset), GFP_KERNEL); + if (!kset) + return NULL; + kobject_set_name(&kset->kobj, name); + kset->uevent_ops = uevent_ops; + kset->kobj.parent = parent_kobj; + + /* + * The kobject of this kset will have a type of kset_ktype and belong to + * no kset itself. That way we can properly free it when it is + * finished being used. + */ + kset->kobj.ktype = &kset_ktype; + kset->kobj.kset = NULL; + + return kset; } /** - * subsystem_create_file - export sysfs attribute file. - * @s: subsystem. - * @a: subsystem attribute descriptor. + * kset_create_and_add - create a struct kset dynamically and add it to sysfs + * + * @name: the name for the kset + * @uevent_ops: a struct kset_uevent_ops for the kset + * @parent_kobj: the parent kobject of this kset, if any. + * + * This function creates a kset structure dynamically and registers it + * with sysfs. When you are finished with this structure, call + * kset_unregister() and the structure will be dynamically freed when it + * is no longer being used. + * + * If the kset was not able to be created, NULL will be returned. */ - -int subsys_create_file(struct kset *s, struct subsys_attribute *a) +struct kset *kset_create_and_add(const char *name, + struct kset_uevent_ops *uevent_ops, + struct kobject *parent_kobj) { - int error = 0; - - if (!s || !a) - return -EINVAL; + struct kset *kset; + int error; - if (kset_get(s)) { - error = sysfs_create_file(&s->kobj, &a->attr); - kset_put(s); + kset = kset_create(name, uevent_ops, parent_kobj); + if (!kset) + return NULL; + error = kset_register(kset); + if (error) { + kfree(kset); + return NULL; } - return error; + return kset; } +EXPORT_SYMBOL_GPL(kset_create_and_add); -EXPORT_SYMBOL(kobject_init); -EXPORT_SYMBOL(kobject_register); -EXPORT_SYMBOL(kobject_unregister); EXPORT_SYMBOL(kobject_get); EXPORT_SYMBOL(kobject_put); -EXPORT_SYMBOL(kobject_add); EXPORT_SYMBOL(kobject_del); EXPORT_SYMBOL(kset_register); EXPORT_SYMBOL(kset_unregister); - -EXPORT_SYMBOL(subsystem_register); -EXPORT_SYMBOL(subsystem_unregister); -EXPORT_SYMBOL(subsys_create_file); diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 5886147252d0d643598e408b63bf193aa49b5f34..5a402e2982afb4a1a82a28092260bb66bd921269 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -98,7 +98,8 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, int i = 0; int retval = 0; - pr_debug("%s\n", __FUNCTION__); + pr_debug("kobject: '%s' (%p): %s\n", + kobject_name(kobj), kobj, __FUNCTION__); /* search the kset we belong to */ top_kobj = kobj; @@ -106,7 +107,9 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, top_kobj = top_kobj->parent; if (!top_kobj->kset) { - pr_debug("kobject attempted to send uevent without kset!\n"); + pr_debug("kobject: '%s' (%p): %s: attempted to send uevent " + "without kset!\n", kobject_name(kobj), kobj, + __FUNCTION__); return -EINVAL; } @@ -116,7 +119,9 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, /* skip the event, if the filter returns zero. */ if (uevent_ops && uevent_ops->filter) if (!uevent_ops->filter(kset, kobj)) { - pr_debug("kobject filter function caused the event to drop!\n"); + pr_debug("kobject: '%s' (%p): %s: filter function " + "caused the event to drop!\n", + kobject_name(kobj), kobj, __FUNCTION__); return 0; } @@ -126,7 +131,9 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, else subsystem = kobject_name(&kset->kobj); if (!subsystem) { - pr_debug("unset subsystem caused the event to drop!\n"); + pr_debug("kobject: '%s' (%p): %s: unset subsystem caused the " + "event to drop!\n", kobject_name(kobj), kobj, + __FUNCTION__); return 0; } @@ -166,12 +173,24 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, if (uevent_ops && uevent_ops->uevent) { retval = uevent_ops->uevent(kset, kobj, env); if (retval) { - pr_debug ("%s - uevent() returned %d\n", - __FUNCTION__, retval); + pr_debug("kobject: '%s' (%p): %s: uevent() returned " + "%d\n", kobject_name(kobj), kobj, + __FUNCTION__, retval); goto exit; } } + /* + * Mark "add" and "remove" events in the object to ensure proper + * events to userspace during automatic cleanup. If the object did + * send an "add" event, "remove" will automatically generated by + * the core, if not already done by the caller. + */ + if (action == KOBJ_ADD) + kobj->state_add_uevent_sent = 1; + else if (action == KOBJ_REMOVE) + kobj->state_remove_uevent_sent = 1; + /* we will send an event, so request a new sequence number */ spin_lock(&sequence_lock); seq = ++uevent_seqnum; @@ -219,11 +238,12 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, retval = add_uevent_var(env, "HOME=/"); if (retval) goto exit; - retval = add_uevent_var(env, "PATH=/sbin:/bin:/usr/sbin:/usr/bin"); + retval = add_uevent_var(env, + "PATH=/sbin:/bin:/usr/sbin:/usr/bin"); if (retval) goto exit; - call_usermodehelper (argv[0], argv, env->envp, UMH_WAIT_EXEC); + call_usermodehelper(argv[0], argv, env->envp, UMH_WAIT_EXEC); } exit: @@ -231,7 +251,6 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, kfree(env); return retval; } - EXPORT_SYMBOL_GPL(kobject_uevent_env); /** @@ -247,7 +266,6 @@ int kobject_uevent(struct kobject *kobj, enum kobject_action action) { return kobject_uevent_env(kobj, action, NULL); } - EXPORT_SYMBOL_GPL(kobject_uevent); /** diff --git a/lib/kref.c b/lib/kref.c index a6dc3ec328e05fc8da4d69d185d13a5758ac0464..9ecd6e86561034f2a097bcc027765704e124f7df 100644 --- a/lib/kref.c +++ b/lib/kref.c @@ -14,14 +14,24 @@ #include <linux/kref.h> #include <linux/module.h> +/** + * kref_set - initialize object and set refcount to requested number. + * @kref: object in question. + * @num: initial reference counter + */ +void kref_set(struct kref *kref, int num) +{ + atomic_set(&kref->refcount, num); + smp_mb(); +} + /** * kref_init - initialize object. * @kref: object in question. */ void kref_init(struct kref *kref) { - atomic_set(&kref->refcount,1); - smp_mb(); + kref_set(kref, 1); } /** @@ -61,6 +71,7 @@ int kref_put(struct kref *kref, void (*release)(struct kref *kref)) return 0; } +EXPORT_SYMBOL(kref_set); EXPORT_SYMBOL(kref_init); EXPORT_SYMBOL(kref_get); EXPORT_SYMBOL(kref_put); diff --git a/mm/slub.c b/mm/slub.c index 474945ecd89d828478fd8048558c2a8d980604b3..5cc4b7dddb505dc08a9a05bdfeb2cc1f91faf9c2 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -3962,7 +3962,7 @@ static struct kset_uevent_ops slab_uevent_ops = { .filter = uevent_filter, }; -static decl_subsys(slab, &slab_ktype, &slab_uevent_ops); +static struct kset *slab_kset; #define ID_STR_LENGTH 64 @@ -4015,7 +4015,7 @@ static int sysfs_slab_add(struct kmem_cache *s) * This is typically the case for debug situations. In that * case we can catch duplicate names easily. */ - sysfs_remove_link(&slab_subsys.kobj, s->name); + sysfs_remove_link(&slab_kset->kobj, s->name); name = s->name; } else { /* @@ -4025,12 +4025,12 @@ static int sysfs_slab_add(struct kmem_cache *s) name = create_unique_id(s); } - kobj_set_kset_s(s, slab_subsys); - kobject_set_name(&s->kobj, name); - kobject_init(&s->kobj); - err = kobject_add(&s->kobj); - if (err) + s->kobj.kset = slab_kset; + err = kobject_init_and_add(&s->kobj, &slab_ktype, NULL, name); + if (err) { + kobject_put(&s->kobj); return err; + } err = sysfs_create_group(&s->kobj, &slab_attr_group); if (err) @@ -4070,9 +4070,8 @@ static int sysfs_slab_alias(struct kmem_cache *s, const char *name) /* * If we have a leftover link then remove it. */ - sysfs_remove_link(&slab_subsys.kobj, name); - return sysfs_create_link(&slab_subsys.kobj, - &s->kobj, name); + sysfs_remove_link(&slab_kset->kobj, name); + return sysfs_create_link(&slab_kset->kobj, &s->kobj, name); } al = kmalloc(sizeof(struct saved_alias), GFP_KERNEL); @@ -4091,8 +4090,8 @@ static int __init slab_sysfs_init(void) struct kmem_cache *s; int err; - err = subsystem_register(&slab_subsys); - if (err) { + slab_kset = kset_create_and_add("slab", &slab_uevent_ops, kernel_kobj); + if (!slab_kset) { printk(KERN_ERR "Cannot register slab subsystem.\n"); return -ENOSYS; } diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 935784f736b3d0f88cff37c76140a5c22a167dd2..298e0f463c56e0aa67d7e876fee6255255b12bc1 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -133,7 +133,7 @@ static void del_nbp(struct net_bridge_port *p) struct net_bridge *br = p->br; struct net_device *dev = p->dev; - sysfs_remove_link(&br->ifobj, dev->name); + sysfs_remove_link(br->ifobj, dev->name); dev_set_promiscuity(dev, -1); @@ -258,12 +258,6 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, p->state = BR_STATE_DISABLED; br_stp_port_timer_init(p); - kobject_init(&p->kobj); - kobject_set_name(&p->kobj, SYSFS_BRIDGE_PORT_ATTR); - p->kobj.ktype = &brport_ktype; - p->kobj.parent = &(dev->dev.kobj); - p->kobj.kset = NULL; - return p; } @@ -379,7 +373,8 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) if (IS_ERR(p)) return PTR_ERR(p); - err = kobject_add(&p->kobj); + err = kobject_init_and_add(&p->kobj, &brport_ktype, &(dev->dev.kobj), + SYSFS_BRIDGE_PORT_ATTR); if (err) goto err0; @@ -416,6 +411,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) br_fdb_delete_by_port(br, p, 1); err1: kobject_del(&p->kobj); + return err; err0: kobject_put(&p->kobj); return err; diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index f666f7b28ff584d7222a9763c95288c6d63da11d..c11b554fd109d4f1b587c8b254a5352889a29b86 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -124,7 +124,7 @@ struct net_bridge struct timer_list tcn_timer; struct timer_list topology_change_timer; struct timer_list gc_timer; - struct kobject ifobj; + struct kobject *ifobj; }; extern struct notifier_block br_device_notifier; diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index 3312e8f2abe47b46e2af85212b93de67adf6c3de..9cf0538d1717e4b633c6bc2e732bd64582b1ca42 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c @@ -426,16 +426,10 @@ int br_sysfs_addbr(struct net_device *dev) goto out2; } - - kobject_set_name(&br->ifobj, SYSFS_BRIDGE_PORT_SUBDIR); - br->ifobj.ktype = NULL; - br->ifobj.kset = NULL; - br->ifobj.parent = brobj; - - err = kobject_register(&br->ifobj); - if (err) { + br->ifobj = kobject_create_and_add(SYSFS_BRIDGE_PORT_SUBDIR, brobj); + if (!br->ifobj) { pr_info("%s: can't add kobject (directory) %s/%s\n", - __FUNCTION__, dev->name, kobject_name(&br->ifobj)); + __FUNCTION__, dev->name, SYSFS_BRIDGE_PORT_SUBDIR); goto out3; } return 0; @@ -453,7 +447,7 @@ void br_sysfs_delbr(struct net_device *dev) struct kobject *kobj = &dev->dev.kobj; struct net_bridge *br = netdev_priv(dev); - kobject_unregister(&br->ifobj); + kobject_put(br->ifobj); sysfs_remove_bin_file(kobj, &bridge_forward); sysfs_remove_group(kobj, &bridge_group); } diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c index 79db51fcb4768dabb001c5afb17325c6ad00a634..02b2d50cce4da640f4b62a6652253d217e890af2 100644 --- a/net/bridge/br_sysfs_if.c +++ b/net/bridge/br_sysfs_if.c @@ -229,7 +229,7 @@ int br_sysfs_addif(struct net_bridge_port *p) goto out2; } - err= sysfs_create_link(&br->ifobj, &p->kobj, p->dev->name); + err = sysfs_create_link(br->ifobj, &p->kobj, p->dev->name); out2: return err; } diff --git a/samples/Kconfig b/samples/Kconfig index 57bb2236952ccc45aed86754855b7c1aff4eca81..74d97cc247872216fc179bf5fdce5b0b9c2cd671 100644 --- a/samples/Kconfig +++ b/samples/Kconfig @@ -13,4 +13,14 @@ config SAMPLE_MARKERS help This build markers example modules. +config SAMPLE_KOBJECT + tristate "Build kobject examples" + help + This config option will allow you to build a number of + different kobject sample modules showing how to use kobjects, + ksets, and ktypes properly. + + If in doubt, say "N" here. + endif # SAMPLES + diff --git a/samples/Makefile b/samples/Makefile index 5a4f0b6bcbedf955a83c39ae46dbca0e42bfb472..8652d0f268ad0fb25e24c65375828ec932df2e96 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -1,3 +1,3 @@ # Makefile for Linux samples code -obj-$(CONFIG_SAMPLES) += markers/ +obj-$(CONFIG_SAMPLES) += markers/ kobject/ diff --git a/samples/kobject/Makefile b/samples/kobject/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4a194203c98254078d2a0f625cf9091cc17cd025 --- /dev/null +++ b/samples/kobject/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_SAMPLE_KOBJECT) += kobject-example.o kset-example.o diff --git a/samples/kobject/kobject-example.c b/samples/kobject/kobject-example.c new file mode 100644 index 0000000000000000000000000000000000000000..08d0d3ff326383510f30baaa4db632e665da64b9 --- /dev/null +++ b/samples/kobject/kobject-example.c @@ -0,0 +1,137 @@ +/* + * Sample kobject implementation + * + * Copyright (C) 2004-2007 Greg Kroah-Hartman <greg@kroah.com> + * Copyright (C) 2007 Novell Inc. + * + * Released under the GPL version 2 only. + * + */ +#include <linux/kobject.h> +#include <linux/string.h> +#include <linux/sysfs.h> +#include <linux/module.h> +#include <linux/init.h> + +/* + * This module shows how to create a simple subdirectory in sysfs called + * /sys/kernel/kobject-example In that directory, 3 files are created: + * "foo", "baz", and "bar". If an integer is written to these files, it can be + * later read out of it. + */ + +static int foo; +static int baz; +static int bar; + +/* + * The "foo" file where a static variable is read from and written to. + */ +static ssize_t foo_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", foo); +} + +static ssize_t foo_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + sscanf(buf, "%du", &foo); + return count; +} + +static struct kobj_attribute foo_attribute = + __ATTR(foo, 0666, foo_show, foo_store); + +/* + * More complex function where we determine which varible is being accessed by + * looking at the attribute for the "baz" and "bar" files. + */ +static ssize_t b_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + int var; + + if (strcmp(attr->attr.name, "baz") == 0) + var = baz; + else + var = bar; + return sprintf(buf, "%d\n", var); +} + +static ssize_t b_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + int var; + + sscanf(buf, "%du", &var); + if (strcmp(attr->attr.name, "baz") == 0) + baz = var; + else + bar = var; + return count; +} + +static struct kobj_attribute baz_attribute = + __ATTR(baz, 0666, b_show, b_store); +static struct kobj_attribute bar_attribute = + __ATTR(bar, 0666, b_show, b_store); + + +/* + * Create a group of attributes so that we can create and destory them all + * at once. + */ +static struct attribute *attrs[] = { + &foo_attribute.attr, + &baz_attribute.attr, + &bar_attribute.attr, + NULL, /* need to NULL terminate the list of attributes */ +}; + +/* + * An unnamed attribute group will put all of the attributes directly in + * the kobject directory. If we specify a name, a subdirectory will be + * created for the attributes with the directory being the name of the + * attribute group. + */ +static struct attribute_group attr_group = { + .attrs = attrs, +}; + +static struct kobject *example_kobj; + +static int example_init(void) +{ + int retval; + + /* + * Create a simple kobject with the name of "kobject_example", + * located under /sys/kernel/ + * + * As this is a simple directory, no uevent will be sent to + * userspace. That is why this function should not be used for + * any type of dynamic kobjects, where the name and number are + * not known ahead of time. + */ + example_kobj = kobject_create_and_add("kobject_example", kernel_kobj); + if (!example_kobj) + return -ENOMEM; + + /* Create the files associated with this kobject */ + retval = sysfs_create_group(example_kobj, &attr_group); + if (retval) + kobject_put(example_kobj); + + return retval; +} + +static void example_exit(void) +{ + kobject_put(example_kobj); +} + +module_init(example_init); +module_exit(example_exit); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com>"); diff --git a/samples/kobject/kset-example.c b/samples/kobject/kset-example.c new file mode 100644 index 0000000000000000000000000000000000000000..b0a1b4fe6584a026866233136d69d19bb3f9d468 --- /dev/null +++ b/samples/kobject/kset-example.c @@ -0,0 +1,278 @@ +/* + * Sample kset and ktype implementation + * + * Copyright (C) 2004-2007 Greg Kroah-Hartman <greg@kroah.com> + * Copyright (C) 2007 Novell Inc. + * + * Released under the GPL version 2 only. + * + */ +#include <linux/kobject.h> +#include <linux/string.h> +#include <linux/sysfs.h> +#include <linux/module.h> +#include <linux/init.h> + +/* + * This module shows how to create a kset in sysfs called + * /sys/kernel/kset-example + * Then tree kobjects are created and assigned to this kset, "foo", "baz", + * and "bar". In those kobjects, attributes of the same name are also + * created and if an integer is written to these files, it can be later + * read out of it. + */ + + +/* + * This is our "object" that we will create a few of and register them with + * sysfs. + */ +struct foo_obj { + struct kobject kobj; + int foo; + int baz; + int bar; +}; +#define to_foo_obj(x) container_of(x, struct foo_obj, kobj) + +/* a custom attribute that works just for a struct foo_obj. */ +struct foo_attribute { + struct attribute attr; + ssize_t (*show)(struct foo_obj *foo, struct foo_attribute *attr, char *buf); + ssize_t (*store)(struct foo_obj *foo, struct foo_attribute *attr, const char *buf, size_t count); +}; +#define to_foo_attr(x) container_of(x, struct foo_attribute, attr) + +/* + * The default show function that must be passed to sysfs. This will be + * called by sysfs for whenever a show function is called by the user on a + * sysfs file associated with the kobjects we have registered. We need to + * transpose back from a "default" kobject to our custom struct foo_obj and + * then call the show function for that specific object. + */ +static ssize_t foo_attr_show(struct kobject *kobj, + struct attribute *attr, + char *buf) +{ + struct foo_attribute *attribute; + struct foo_obj *foo; + + attribute = to_foo_attr(attr); + foo = to_foo_obj(kobj); + + if (!attribute->show) + return -EIO; + + return attribute->show(foo, attribute, buf); +} + +/* + * Just like the default show function above, but this one is for when the + * sysfs "store" is requested (when a value is written to a file.) + */ +static ssize_t foo_attr_store(struct kobject *kobj, + struct attribute *attr, + const char *buf, size_t len) +{ + struct foo_attribute *attribute; + struct foo_obj *foo; + + attribute = to_foo_attr(attr); + foo = to_foo_obj(kobj); + + if (!attribute->store) + return -EIO; + + return attribute->store(foo, attribute, buf, len); +} + +/* Our custom sysfs_ops that we will associate with our ktype later on */ +static struct sysfs_ops foo_sysfs_ops = { + .show = foo_attr_show, + .store = foo_attr_store, +}; + +/* + * The release function for our object. This is REQUIRED by the kernel to + * have. We free the memory held in our object here. + * + * NEVER try to get away with just a "blank" release function to try to be + * smarter than the kernel. Turns out, no one ever is... + */ +static void foo_release(struct kobject *kobj) +{ + struct foo_obj *foo; + + foo = to_foo_obj(kobj); + kfree(foo); +} + +/* + * The "foo" file where the .foo variable is read from and written to. + */ +static ssize_t foo_show(struct foo_obj *foo_obj, struct foo_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", foo_obj->foo); +} + +static ssize_t foo_store(struct foo_obj *foo_obj, struct foo_attribute *attr, + const char *buf, size_t count) +{ + sscanf(buf, "%du", &foo_obj->foo); + return count; +} + +static struct foo_attribute foo_attribute = + __ATTR(foo, 0666, foo_show, foo_store); + +/* + * More complex function where we determine which varible is being accessed by + * looking at the attribute for the "baz" and "bar" files. + */ +static ssize_t b_show(struct foo_obj *foo_obj, struct foo_attribute *attr, + char *buf) +{ + int var; + + if (strcmp(attr->attr.name, "baz") == 0) + var = foo_obj->baz; + else + var = foo_obj->bar; + return sprintf(buf, "%d\n", var); +} + +static ssize_t b_store(struct foo_obj *foo_obj, struct foo_attribute *attr, + const char *buf, size_t count) +{ + int var; + + sscanf(buf, "%du", &var); + if (strcmp(attr->attr.name, "baz") == 0) + foo_obj->baz = var; + else + foo_obj->bar = var; + return count; +} + +static struct foo_attribute baz_attribute = + __ATTR(baz, 0666, b_show, b_store); +static struct foo_attribute bar_attribute = + __ATTR(bar, 0666, b_show, b_store); + +/* + * Create a group of attributes so that we can create and destory them all + * at once. + */ +static struct attribute *foo_default_attrs[] = { + &foo_attribute.attr, + &baz_attribute.attr, + &bar_attribute.attr, + NULL, /* need to NULL terminate the list of attributes */ +}; + +/* + * Our own ktype for our kobjects. Here we specify our sysfs ops, the + * release function, and the set of default attributes we want created + * whenever a kobject of this type is registered with the kernel. + */ +static struct kobj_type foo_ktype = { + .sysfs_ops = &foo_sysfs_ops, + .release = foo_release, + .default_attrs = foo_default_attrs, +}; + +static struct kset *example_kset; +static struct foo_obj *foo_obj; +static struct foo_obj *bar_obj; +static struct foo_obj *baz_obj; + +static struct foo_obj *create_foo_obj(const char *name) +{ + struct foo_obj *foo; + int retval; + + /* allocate the memory for the whole object */ + foo = kzalloc(sizeof(*foo), GFP_KERNEL); + if (!foo) + return NULL; + + /* + * As we have a kset for this kobject, we need to set it before calling + * the kobject core. + */ + foo->kobj.kset = example_kset; + + /* + * Initialize and add the kobject to the kernel. All the default files + * will be created here. As we have already specified a kset for this + * kobject, we don't have to set a parent for the kobject, the kobject + * will be placed beneath that kset automatically. + */ + retval = kobject_init_and_add(&foo->kobj, &foo_ktype, NULL, "%s", name); + if (retval) { + kfree(foo); + return NULL; + } + + /* + * We are always responsible for sending the uevent that the kobject + * was added to the system. + */ + kobject_uevent(&foo->kobj, KOBJ_ADD); + + return foo; +} + +static void destroy_foo_obj(struct foo_obj *foo) +{ + kobject_put(&foo->kobj); +} + +static int example_init(void) +{ + /* + * Create a kset with the name of "kset_example", + * located under /sys/kernel/ + */ + example_kset = kset_create_and_add("kset_example", NULL, kernel_kobj); + if (!example_kset) + return -ENOMEM; + + /* + * Create three objects and register them with our kset + */ + foo_obj = create_foo_obj("foo"); + if (!foo_obj) + goto foo_error; + + bar_obj = create_foo_obj("bar"); + if (!bar_obj) + goto bar_error; + + baz_obj = create_foo_obj("baz"); + if (!baz_obj) + goto baz_error; + + return 0; + +baz_error: + destroy_foo_obj(bar_obj); +bar_error: + destroy_foo_obj(foo_obj); +foo_error: + return -EINVAL; +} + +static void example_exit(void) +{ + destroy_foo_obj(baz_obj); + destroy_foo_obj(bar_obj); + destroy_foo_obj(foo_obj); + kset_unregister(example_kset); +} + +module_init(example_init); +module_exit(example_exit); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com>"); diff --git a/security/inode.c b/security/inode.c index b28a8acae34d7082dcb52519f1ebb927a2e1c9ae..acc6cf0d79001fa06d53c5b592fb4c90f5ea88a2 100644 --- a/security/inode.c +++ b/security/inode.c @@ -315,20 +315,19 @@ void securityfs_remove(struct dentry *dentry) } EXPORT_SYMBOL_GPL(securityfs_remove); -static decl_subsys(security, NULL, NULL); +static struct kobject *security_kobj; static int __init securityfs_init(void) { int retval; - kobj_set_kset_s(&security_subsys, kernel_subsys); - retval = subsystem_register(&security_subsys); - if (retval) - return retval; + security_kobj = kobject_create_and_add("security", kernel_kobj); + if (!security_kobj) + return -EINVAL; retval = register_filesystem(&fs_type); if (retval) - subsystem_unregister(&security_subsys); + kobject_put(security_kobj); return retval; }