diff options
330 files changed, 25830 insertions, 9021 deletions
diff --git a/Documentation/crypto/api-intro.txt b/Documentation/crypto/api-intro.txt index a2ac6d294793..8b49302712a8 100644 --- a/Documentation/crypto/api-intro.txt +++ b/Documentation/crypto/api-intro.txt @@ -33,9 +33,16 @@ The idea is to make the user interface and algorithm registration API very simple, while hiding the core logic from both. Many good ideas from existing APIs such as Cryptoapi and Nettle have been adapted for this. -The API currently supports three types of transforms: Ciphers, Digests and -Compressors. The compression algorithms especially seem to be performing -very well so far. +The API currently supports five main types of transforms: AEAD (Authenticated +Encryption with Associated Data), Block Ciphers, Ciphers, Compressors and +Hashes. + +Please note that Block Ciphers is somewhat of a misnomer. It is in fact +meant to support all ciphers including stream ciphers. The difference +between Block Ciphers and Ciphers is that the latter operates on exactly +one block while the former can operate on an arbitrary amount of data, +subject to block size requirements (i.e., non-stream ciphers can only +process multiples of blocks). Support for hardware crypto devices via an asynchronous interface is under development. @@ -69,29 +76,12 @@ Here's an example of how to use the API: Many real examples are available in the regression test module (tcrypt.c). -CONFIGURATION NOTES - -As Triple DES is part of the DES module, for those using modular builds, -add the following line to /etc/modprobe.conf: - - alias des3_ede des - -The Null algorithms reside in the crypto_null module, so these lines -should also be added: - - alias cipher_null crypto_null - alias digest_null crypto_null - alias compress_null crypto_null - -The SHA384 algorithm shares code within the SHA512 module, so you'll -also need: - alias sha384 sha512 - - DEVELOPER NOTES Transforms may only be allocated in user context, and cryptographic -methods may only be called from softirq and user contexts. +methods may only be called from softirq and user contexts. For +transforms with a setkey method it too should only be called from +user context. When using the API for ciphers, performance will be optimal if each scatterlist contains data which is a multiple of the cipher's block @@ -130,8 +120,9 @@ might already be working on. BUGS Send bug reports to: -Herbert Xu <herbert@gondor.apana.org.au> -Cc: David S. Miller <davem@redhat.com> +linux-crypto@vger.kernel.org +Cc: Herbert Xu <herbert@gondor.apana.org.au>, + David S. Miller <davem@redhat.com> FURTHER INFORMATION diff --git a/Documentation/kobject.txt b/Documentation/kobject.txt index ca86a885ad8f..bf3256e04027 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 481faf515d53..a327db67782a 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 3081927cc2d6..c4b7b2bd369a 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 7047696c47a1..488c1f31b992 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 d17f324db9f5..dcf8bcf846d6 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 000000000000..ecd9307a641f --- /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 48fc67bfbe3d..3d80e8af36ec 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 000000000000..5f4815c63ec7 --- /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 000000000000..985c92e20b73 --- /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 000000000000..9312608ffb8d --- /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 000000000000..75992a603ae3 --- /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 000000000000..b5b9b0ab02fd --- /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 000000000000..ba8149d2233a --- /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 1533d3ecd7a0..f6f3689a86ee 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 72280754354d..df37e93c6fc9 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 3bf01e28df33..d9805e3d9304 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 177664ccb2e2..a16349272f54 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 26116440a7c9..78ebad063cba 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 011a1a72b61c..1d3112dc629e 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 a4bc3483cbb3..41d8c6cea62b 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 e580303cb0ab..0e7991940f81 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 4f92a1562d77..265cd3f567a3 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 c326983f4a8f..78af7664988b 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 8d8117158d23..9ce490560af9 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 edf3347d9c5b..3dc17d7bf38e 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 a9de727c9327..0a5cf3a6438b 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 6097753394ad..b2a87b8ef673 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 29696e46ed65..aae1b9cbaf44 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 3444b13afac5..f197bb3a2366 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 7014a3571ec0..36a46c3ae308 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 11f9895ded50..f4bdc1dfa320 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 14261fee5f4d..a2484fc1a06c 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 471013577108..197d7977de35 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 c83c3e3f5178..a08862203643 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 999f5e160897..84c0d4ef76a2 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 73e69023d90a..e95fc1594c84 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 05a56e55804c..e898ff4d2b97 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 e47938899a92..212a94f5d34b 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 e1c0fd6dbc1a..f59444d3be75 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 9192777d0f78..4f163e20939e 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 18ec94733293..da36522d327a 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 d585207f9f77..449075a04798 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/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index 512669691ad0..46c97058ebe1 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -6,6 +6,7 @@ * s390 Version: * Copyright IBM Corp. 2005,2007 * Author(s): Jan Glauber (jang@de.ibm.com) + * Sebastian Siewior (sebastian@breakpoint.cc> SW-Fallback * * Derived from "crypto/aes_generic.c" * @@ -16,17 +17,13 @@ * */ +#include <crypto/aes.h> #include <crypto/algapi.h> +#include <linux/err.h> #include <linux/module.h> #include <linux/init.h> #include "crypt_s390.h" -#define AES_MIN_KEY_SIZE 16 -#define AES_MAX_KEY_SIZE 32 - -/* data block size for all key lengths */ -#define AES_BLOCK_SIZE 16 - #define AES_KEYLEN_128 1 #define AES_KEYLEN_192 2 #define AES_KEYLEN_256 4 @@ -39,45 +36,89 @@ struct s390_aes_ctx { long enc; long dec; int key_len; + union { + struct crypto_blkcipher *blk; + struct crypto_cipher *cip; + } fallback; }; -static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, - unsigned int key_len) +/* + * Check if the key_len is supported by the HW. + * Returns 0 if it is, a positive number if it is not and software fallback is + * required or a negative number in case the key size is not valid + */ +static int need_fallback(unsigned int key_len) { - struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); - u32 *flags = &tfm->crt_flags; - switch (key_len) { case 16: if (!(keylen_flag & AES_KEYLEN_128)) - goto fail; + return 1; break; case 24: if (!(keylen_flag & AES_KEYLEN_192)) - goto fail; - + return 1; break; case 32: if (!(keylen_flag & AES_KEYLEN_256)) - goto fail; + return 1; break; default: - goto fail; + return -1; break; } + return 0; +} + +static int setkey_fallback_cip(struct crypto_tfm *tfm, const u8 *in_key, + unsigned int key_len) +{ + struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); + int ret; + + sctx->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK; + sctx->fallback.blk->base.crt_flags |= (tfm->crt_flags & + CRYPTO_TFM_REQ_MASK); + + ret = crypto_cipher_setkey(sctx->fallback.cip, in_key, key_len); + if (ret) { + tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; + tfm->crt_flags |= (sctx->fallback.blk->base.crt_flags & + CRYPTO_TFM_RES_MASK); + } + return ret; +} + +static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, + unsigned int key_len) +{ + struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); + u32 *flags = &tfm->crt_flags; + int ret; + + ret = need_fallback(key_len); + if (ret < 0) { + *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } sctx->key_len = key_len; - memcpy(sctx->key, in_key, key_len); - return 0; -fail: - *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; - return -EINVAL; + if (!ret) { + memcpy(sctx->key, in_key, key_len); + return 0; + } + + return setkey_fallback_cip(tfm, in_key, key_len); } static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { const struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); + if (unlikely(need_fallback(sctx->key_len))) { + crypto_cipher_encrypt_one(sctx->fallback.cip, out, in); + return; + } + switch (sctx->key_len) { case 16: crypt_s390_km(KM_AES_128_ENCRYPT, &sctx->key, out, in, @@ -98,6 +139,11 @@ static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { const struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); + if (unlikely(need_fallback(sctx->key_len))) { + crypto_cipher_decrypt_one(sctx->fallback.cip, out, in); + return; + } + switch (sctx->key_len) { case 16: crypt_s390_km(KM_AES_128_DECRYPT, &sctx->key, out, in, @@ -114,6 +160,29 @@ static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) } } +static int fallback_init_cip(struct crypto_tfm *tfm) +{ + const char *name = tfm->__crt_alg->cra_name; + struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); + + sctx->fallback.cip = crypto_alloc_cipher(name, 0, + CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); + + if (IS_ERR(sctx->fallback.cip)) { + printk(KERN_ERR "Error allocating fallback algo %s\n", name); + return PTR_ERR(sctx->fallback.blk); + } + + return 0; +} + +static void fallback_exit_cip(struct crypto_tfm *tfm) +{ + struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); + + crypto_free_cipher(sctx->fallback.cip); + sctx->fallback.cip = NULL; +} static struct crypto_alg aes_alg = { .cra_name = "aes", @@ -125,6 +194,8 @@ static struct crypto_alg aes_alg = { .cra_ctxsize = sizeof(struct s390_aes_ctx), .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), + .cra_init = fallback_init_cip, + .cra_exit = fallback_exit_cip, .cra_u = { .cipher = { .cia_min_keysize = AES_MIN_KEY_SIZE, @@ -136,10 +207,70 @@ static struct crypto_alg aes_alg = { } }; +static int setkey_fallback_blk(struct crypto_tfm *tfm, const u8 *key, + unsigned int len) +{ + struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); + unsigned int ret; + + sctx->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK; + sctx->fallback.blk->base.crt_flags |= (tfm->crt_flags & + CRYPTO_TFM_REQ_MASK); + + ret = crypto_blkcipher_setkey(sctx->fallback.blk, key, len); + if (ret) { + tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; + tfm->crt_flags |= (sctx->fallback.blk->base.crt_flags & + CRYPTO_TFM_RES_MASK); + } + return ret; +} + +static int fallback_blk_dec(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + unsigned int ret; + struct crypto_blkcipher *tfm; + struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + + tfm = desc->tfm; + desc->tfm = sctx->fallback.blk; + + ret = crypto_blkcipher_decrypt_iv(desc, dst, src, nbytes); + + desc->tfm = tfm; + return ret; +} + +static int fallback_blk_enc(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + unsigned int ret; + struct crypto_blkcipher *tfm; + struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + + tfm = desc->tfm; + desc->tfm = sctx->fallback.blk; + + ret = crypto_blkcipher_encrypt_iv(desc, dst, src, nbytes); + + desc->tfm = tfm; + return ret; +} + static int ecb_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, unsigned int key_len) { struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); + int ret; + + ret = need_fallback(key_len); + if (ret > 0) { + sctx->key_len = key_len; + return setkey_fallback_blk(tfm, in_key, key_len); + } switch (key_len) { case 16: @@ -188,6 +319,9 @@ static int ecb_aes_encrypt(struct blkcipher_desc *desc, struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; + if (unlikely(need_fallback(sctx->key_len))) + return fallback_blk_enc(desc, dst, src, nbytes); + blkcipher_walk_init(&walk, dst, src, nbytes); return ecb_aes_crypt(desc, sctx->enc, sctx->key, &walk); } @@ -199,10 +333,37 @@ static int ecb_aes_decrypt(struct blkcipher_desc *desc, struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; + if (unlikely(need_fallback(sctx->key_len))) + return fallback_blk_dec(desc, dst, src, nbytes); + blkcipher_walk_init(&walk, dst, src, nbytes); return ecb_aes_crypt(desc, sctx->dec, sctx->key, &walk); } +static int fallback_init_blk(struct crypto_tfm *tfm) +{ + const char *name = tfm->__crt_alg->cra_name; + struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); + + sctx->fallback.blk = crypto_alloc_blkcipher(name, 0, + CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); + + if (IS_ERR(sctx->fallback.blk)) { + printk(KERN_ERR "Error allocating fallback algo %s\n", name); + return PTR_ERR(sctx->fallback.blk); + } + + return 0; +} + +static void fallback_exit_blk(struct crypto_tfm *tfm) +{ + struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); + + crypto_free_blkcipher(sctx->fallback.blk); + sctx->fallback.blk = NULL; +} + static struct crypto_alg ecb_aes_alg = { .cra_name = "ecb(aes)", .cra_driver_name = "ecb-aes-s390", @@ -214,6 +375,8 @@ static struct crypto_alg ecb_aes_alg = { .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(ecb_aes_alg.cra_list), + .cra_init = fallback_init_blk, + .cra_exit = fallback_exit_blk, .cra_u = { .blkcipher = { .min_keysize = AES_MIN_KEY_SIZE, @@ -229,6 +392,13 @@ static int cbc_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, unsigned int key_len) { struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); + int ret; + + ret = need_fallback(key_len); + if (ret > 0) { + sctx->key_len = key_len; + return setkey_fallback_blk(tfm, in_key, key_len); + } switch (key_len) { case 16: @@ -283,6 +453,9 @@ static int cbc_aes_encrypt(struct blkcipher_desc *desc, struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; + if (unlikely(need_fallback(sctx->key_len))) + return fallback_blk_enc(desc, dst, src, nbytes); + blkcipher_walk_init(&walk, dst, src, nbytes); return cbc_aes_crypt(desc, sctx->enc, sctx->iv, &walk); } @@ -294,6 +467,9 @@ static int cbc_aes_decrypt(struct blkcipher_desc *desc, struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; + if (unlikely(need_fallback(sctx->key_len))) + return fallback_blk_dec(desc, dst, src, nbytes); + blkcipher_walk_init(&walk, dst, src, nbytes); return cbc_aes_crypt(desc, sctx->dec, sctx->iv, &walk); } @@ -309,6 +485,8 @@ static struct crypto_alg cbc_aes_alg = { .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(cbc_aes_alg.cra_list), + .cra_init = fallback_init_blk, + .cra_exit = fallback_exit_blk, .cra_u = { .blkcipher = { .min_keysize = AES_MIN_KEY_SIZE, @@ -336,14 +514,10 @@ static int __init aes_init(void) return -EOPNOTSUPP; /* z9 109 and z9 BC/EC only support 128 bit key length */ - if (keylen_flag == AES_KEYLEN_128) { - aes_alg.cra_u.cipher.cia_max_keysize = AES_MIN_KEY_SIZE; - ecb_aes_alg.cra_u.blkcipher.max_keysize = AES_MIN_KEY_SIZE; - cbc_aes_alg.cra_u.blkcipher.max_keysize = AES_MIN_KEY_SIZE; + if (keylen_flag == AES_KEYLEN_128) printk(KERN_INFO "aes_s390: hardware acceleration only available for" "128 bit keys\n"); - } ret = crypto_register_alg(&aes_alg); if (ret) @@ -382,4 +556,3 @@ MODULE_ALIAS("aes"); MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm"); MODULE_LICENSE("GPL"); - diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index 5245717295b8..4b010ff814c9 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 ce0856d32500..b97694fa62ec 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 22b800ce2126..3bbac1293be4 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 eebcd4768bbf..51b57c0d1a3c 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 b22a78c807e6..3008c00eea6b 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 a3a67d151e52..2bc04bfee738 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/crypto/Makefile b/arch/x86/crypto/Makefile index 46bb609e2444..3874c2de5403 100644 --- a/arch/x86/crypto/Makefile +++ b/arch/x86/crypto/Makefile @@ -4,12 +4,16 @@ obj-$(CONFIG_CRYPTO_AES_586) += aes-i586.o obj-$(CONFIG_CRYPTO_TWOFISH_586) += twofish-i586.o +obj-$(CONFIG_CRYPTO_SALSA20_586) += salsa20-i586.o obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o +obj-$(CONFIG_CRYPTO_SALSA20_X86_64) += salsa20-x86_64.o -aes-i586-y := aes-i586-asm_32.o aes_32.o -twofish-i586-y := twofish-i586-asm_32.o twofish_32.o +aes-i586-y := aes-i586-asm_32.o aes_glue.o +twofish-i586-y := twofish-i586-asm_32.o twofish_glue.o +salsa20-i586-y := salsa20-i586-asm_32.o salsa20_glue.o -aes-x86_64-y := aes-x86_64-asm_64.o aes_64.o -twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_64.o +aes-x86_64-y := aes-x86_64-asm_64.o aes_glue.o +twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_glue.o +salsa20-x86_64-y := salsa20-x86_64-asm_64.o salsa20_glue.o diff --git a/arch/x86/crypto/aes-i586-asm_32.S b/arch/x86/crypto/aes-i586-asm_32.S index f942f0c8f630..1093bede3e0a 100644 --- a/arch/x86/crypto/aes-i586-asm_32.S +++ b/arch/x86/crypto/aes-i586-asm_32.S @@ -46,9 +46,9 @@ #define in_blk 16 /* offsets in crypto_tfm structure */ -#define ekey (crypto_tfm_ctx_offset + 0) -#define nrnd (crypto_tfm_ctx_offset + 256) -#define dkey (crypto_tfm_ctx_offset + 260) +#define klen (crypto_tfm_ctx_offset + 0) +#define ekey (crypto_tfm_ctx_offset + 4) +#define dkey (crypto_tfm_ctx_offset + 244) // register mapping for encrypt and decrypt subroutines @@ -221,8 +221,8 @@ .global aes_enc_blk -.extern ft_tab -.extern fl_tab +.extern crypto_ft_tab +.extern crypto_fl_tab .align 4 @@ -236,7 +236,7 @@ aes_enc_blk: 1: push %ebx mov in_blk+4(%esp),%r2 push %esi - mov nrnd(%ebp),%r3 // number of rounds + mov klen(%ebp),%r3 // key size push %edi #if ekey != 0 lea ekey(%ebp),%ebp // key pointer @@ -255,26 +255,26 @@ aes_enc_blk: sub $8,%esp // space for register saves on stack add $16,%ebp // increment to next round key - cmp $12,%r3 + cmp $24,%r3 jb 4f // 10 rounds for 128-bit key lea 32(%ebp),%ebp je 3f // 12 rounds for 192-bit key lea 32(%ebp),%ebp -2: fwd_rnd1( -64(%ebp) ,ft_tab) // 14 rounds for 256-bit key - fwd_rnd2( -48(%ebp) ,ft_tab) -3: fwd_rnd1( -32(%ebp) ,ft_tab) // 12 rounds for 192-bit key - fwd_rnd2( -16(%ebp) ,ft_tab) -4: fwd_rnd1( (%ebp) ,ft_tab) // 10 rounds for 128-bit key - fwd_rnd2( +16(%ebp) ,ft_tab) - fwd_rnd1( +32(%ebp) ,ft_tab) - fwd_rnd2( +48(%ebp) ,ft_tab) - fwd_rnd1( +64(%ebp) ,ft_tab) - fwd_rnd2( +80(%ebp) ,ft_tab) - fwd_rnd1( +96(%ebp) ,ft_tab) - fwd_rnd2(+112(%ebp) ,ft_tab) - fwd_rnd1(+128(%ebp) ,ft_tab) - fwd_rnd2(+144(%ebp) ,fl_tab) // last round uses a different table +2: fwd_rnd1( -64(%ebp), crypto_ft_tab) // 14 rounds for 256-bit key + fwd_rnd2( -48(%ebp), crypto_ft_tab) +3: fwd_rnd1( -32(%ebp), crypto_ft_tab) // 12 rounds for 192-bit key + fwd_rnd2( -16(%ebp), crypto_ft_tab) +4: fwd_rnd1( (%ebp), crypto_ft_tab) // 10 rounds for 128-bit key + fwd_rnd2( +16(%ebp), crypto_ft_tab) + fwd_rnd1( +32(%ebp), crypto_ft_tab) + fwd_rnd2( +48(%ebp), crypto_ft_tab) + fwd_rnd1( +64(%ebp), crypto_ft_tab) + fwd_rnd2( +80(%ebp), crypto_ft_tab) + fwd_rnd1( +96(%ebp), crypto_ft_tab) + fwd_rnd2(+112(%ebp), crypto_ft_tab) + fwd_rnd1(+128(%ebp), crypto_ft_tab) + fwd_rnd2(+144(%ebp), crypto_fl_tab) // last round uses a different table // move final values to the output array. CAUTION: the // order of these assigns rely on the register mappings @@ -297,8 +297,8 @@ aes_enc_blk: .global aes_dec_blk -.extern it_tab -.extern il_tab +.extern crypto_it_tab +.extern crypto_il_tab .align 4 @@ -312,14 +312,11 @@ aes_dec_blk: 1: push %ebx mov in_blk+4(%esp),%r2 push %esi - mov nrnd(%ebp),%r3 // number of rounds + mov klen(%ebp),%r3 // key size push %edi #if dkey != 0 lea dkey(%ebp),%ebp // key pointer #endif - mov %r3,%r0 - shl $4,%r0 - add %r0,%ebp // input four columns and xor in first round key @@ -333,27 +330,27 @@ aes_dec_blk: xor 12(%ebp),%r5 sub $8,%esp // space for register saves on stack - sub $16,%ebp // increment to next round key - cmp $12,%r3 + add $16,%ebp // increment to next round key + cmp $24,%r3 jb 4f // 10 rounds for 128-bit key - lea -32(%ebp),%ebp + lea 32(%ebp),%ebp je 3f // 12 rounds for 192-bit key - lea -32(%ebp),%ebp - -2: inv_rnd1( +64(%ebp), it_tab) // 14 rounds for 256-bit key - inv_rnd2( +48(%ebp), it_tab) -3: inv_rnd1( +32(%ebp), it_tab) // 12 rounds for 192-bit key - inv_rnd2( +16(%ebp), it_tab) -4: inv_rnd1( (%ebp), it_tab) // 10 rounds for 128-bit key - inv_rnd2( -16(%ebp), it_tab) - inv_rnd1( -32(%ebp), it_tab) - inv_rnd2( -48(%ebp), it_tab) - inv_rnd1( -64(%ebp), it_tab) - inv_rnd2( -80(%ebp), it_tab) - inv_rnd1( -96(%ebp), it_tab) - inv_rnd2(-112(%ebp), it_tab) - inv_rnd1(-128(%ebp), it_tab) - inv_rnd2(-144(%ebp), il_tab) // last round uses a different table + lea 32(%ebp),%ebp + +2: inv_rnd1( -64(%ebp), crypto_it_tab) // 14 rounds for 256-bit key + inv_rnd2( -48(%ebp), crypto_it_tab) +3: inv_rnd1( -32(%ebp), crypto_it_tab) // 12 rounds for 192-bit key + inv_rnd2( -16(%ebp), crypto_it_tab) +4: inv_rnd1( (%ebp), crypto_it_tab) // 10 rounds for 128-bit key + inv_rnd2( +16(%ebp), crypto_it_tab) + inv_rnd1( +32(%ebp), crypto_it_tab) + inv_rnd2( +48(%ebp), crypto_it_tab) + inv_rnd1( +64(%ebp), crypto_it_tab) + inv_rnd2( +80(%ebp), crypto_it_tab) + inv_rnd1( +96(%ebp), crypto_it_tab) + inv_rnd2(+112(%ebp), crypto_it_tab) + inv_rnd1(+128(%ebp), crypto_it_tab) + inv_rnd2(+144(%ebp), crypto_il_tab) // last round uses a different table // move final values to the output array. CAUTION: the // order of these assigns rely on the register mappings diff --git a/arch/x86/crypto/aes-x86_64-asm_64.S b/arch/x86/crypto/aes-x86_64-asm_64.S index 26b40de4d0b0..a120f526c3df 100644 --- a/arch/x86/crypto/aes-x86_64-asm_64.S +++ b/arch/x86/crypto/aes-x86_64-asm_64.S @@ -8,10 +8,10 @@ * including this sentence is retained in full. */ -.extern aes_ft_tab -.extern aes_it_tab -.extern aes_fl_tab -.extern aes_il_tab +.extern crypto_ft_tab +.extern crypto_it_tab +.extern crypto_fl_tab +.extern crypto_il_tab .text @@ -56,13 +56,13 @@ .align 8; \ FUNC: movq r1,r2; \ movq r3,r4; \ - leaq BASE+KEY+52(r8),r9; \ + leaq BASE+KEY+48+4(r8),r9; \ movq r10,r11; \ movl (r7),r5 ## E; \ movl 4(r7),r1 ## E; \ movl 8(r7),r6 ## E; \ movl 12(r7),r7 ## E; \ - movl BASE(r8),r10 ## E; \ + movl BASE+0(r8),r10 ## E; \ xorl -48(r9),r5 ## E; \ xorl -44(r9),r1 ## E; \ xorl -40(r9),r6 ## E; \ @@ -154,37 +154,37 @@ FUNC: movq r1,r2; \ /* void aes_enc_blk(stuct crypto_tfm *tfm, u8 *out, const u8 *in) */ entry(aes_enc_blk,0,enc128,enc192) - encrypt_round(aes_ft_tab,-96) - encrypt_round(aes_ft_tab,-80) -enc192: encrypt_round(aes_ft_tab,-64) - encrypt_round(aes_ft_tab,-48) -enc128: encrypt_round(aes_ft_tab,-32) - encrypt_round(aes_ft_tab,-16) - encrypt_round(aes_ft_tab, 0) - encrypt_round(aes_ft_tab, 16) - encrypt_round(aes_ft_tab, 32) - encrypt_round(aes_ft_tab, 48) - encrypt_round(aes_ft_tab, 64) - encrypt_round(aes_ft_tab, 80) - encrypt_round(aes_ft_tab, 96) - encrypt_final(aes_fl_tab,112) + encrypt_round(crypto_ft_tab,-96) + encrypt_round(crypto_ft_tab,-80) +enc192: encrypt_round(crypto_ft_tab,-64) + encrypt_round(crypto_ft_tab,-48) +enc128: encrypt_round(crypto_ft_tab,-32) + encrypt_round(crypto_ft_tab,-16) + encrypt_round(crypto_ft_tab, 0) + encrypt_round(crypto_ft_tab, 16) + encrypt_round(crypto_ft_tab, 32) + encrypt_round(crypto_ft_tab, 48) + encrypt_round(crypto_ft_tab, 64) + encrypt_round(crypto_ft_tab, 80) + encrypt_round(crypto_ft_tab, 96) + encrypt_final(crypto_fl_tab,112) return /* void aes_dec_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in) */ entry(aes_dec_blk,240,dec128,dec192) - decrypt_round(aes_it_tab,-96) - decrypt_round(aes_it_tab,-80) -dec192: decrypt_round(aes_it_tab,-64) - decrypt_round(aes_it_tab,-48) -dec128: decrypt_round(aes_it_tab,-32) - decrypt_round(aes_it_tab,-16) - decrypt_round(aes_it_tab, 0) - decrypt_round(aes_it_tab, 16) - decrypt_round(aes_it_tab, 32) - decrypt_round(aes_it_tab, 48) - decrypt_round(aes_it_tab, 64) - decrypt_round(aes_it_tab, 80) - decrypt_round(aes_it_tab, 96) - decrypt_final(aes_il_tab,112) + decrypt_round(crypto_it_tab,-96) + decrypt_round(crypto_it_tab,-80) +dec192: decrypt_round(crypto_it_tab,-64) + decrypt_round(crypto_it_tab,-48) +dec128: decrypt_round(crypto_it_tab,-32) + decrypt_round(crypto_it_tab,-16) + decrypt_round(crypto_it_tab, 0) + decrypt_round(crypto_it_tab, 16) + decrypt_round(crypto_it_tab, 32) + decrypt_round(crypto_it_tab, 48) + decrypt_round(crypto_it_tab, 64) + decrypt_round(crypto_it_tab, 80) + decrypt_round(crypto_it_tab, 96) + decrypt_final(crypto_il_tab,112) return diff --git a/arch/x86/crypto/aes_32.c b/arch/x86/crypto/aes_32.c deleted file mode 100644 index 49aad9397f10..000000000000 --- a/arch/x86/crypto/aes_32.c +++ /dev/null @@ -1,515 +0,0 @@ -/* - * - * Glue Code for optimized 586 assembler version of AES - * - * Copyright (c) 2002, Dr Brian Gladman <>, Worcester, UK. - * All rights reserved. - * - * LICENSE TERMS - * - * The free distribution and use of this software in both source and binary - * form is allowed (with or without changes) provided that: - * - * 1. distributions of this source code include the above copyright - * notice, this list of conditions and the following disclaimer; - * - * 2. distributions in binary form include the above copyright - * notice, this list of conditions and the following disclaimer - * in the documentation and/or other associated materials; - * - * 3. the copyright holder's name is not used to endorse products - * built using this software without specific written permission. - * - * ALTERNATIVELY, provided that this notice is retained in full, this product - * may be distributed under the terms of the GNU General Public License (GPL), - * in which case the provisions of the GPL apply INSTEAD OF those given above. - * - * DISCLAIMER - * - * This software is provided 'as is' with no explicit or implied warranties - * in respect of its properties, including, but not limited to, correctness - * and/or fitness for purpose. - * - * Copyright (c) 2003, Adam J. Richter <adam@yggdrasil.com> (conversion to - * 2.5 API). - * Copyright (c) 2003, 2004 Fruhwirth Clemens <clemens@endorphin.org> - * Copyright (c) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com> - * - */ - -#include <asm/byteorder.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/types.h> -#include <linux/crypto.h> -#include <linux/linkage.h> - -asmlinkage void aes_enc_blk(struct crypto_tfm *tfm, u8 *dst, const u8 *src); -asmlinkage void aes_dec_blk(struct crypto_tfm *tfm, u8 *dst, const u8 *src); - -#define AES_MIN_KEY_SIZE 16 -#define AES_MAX_KEY_SIZE 32 -#define AES_BLOCK_SIZE 16 -#define AES_KS_LENGTH 4 * AES_BLOCK_SIZE -#define RC_LENGTH 29 - -struct aes_ctx { - u32 ekey[AES_KS_LENGTH]; - u32 rounds; - u32 dkey[AES_KS_LENGTH]; -}; - -#define WPOLY 0x011b -#define bytes2word(b0, b1, b2, b3) \ - (((u32)(b3) << 24) | ((u32)(b2) << 16) | ((u32)(b1) << 8) | (b0)) - -/* define the finite field multiplies required for Rijndael */ -#define f2(x) ((x) ? pow[log[x] + 0x19] : 0) -#define f3(x) ((x) ? pow[log[x] + 0x01] : 0) -#define f9(x) ((x) ? pow[log[x] + 0xc7] : 0) -#define fb(x) ((x) ? pow[log[x] + 0x68] : 0) -#define fd(x) ((x) ? pow[log[x] + 0xee] : 0) -#define fe(x) ((x) ? pow[log[x] + 0xdf] : 0) -#define fi(x) ((x) ? pow[255 - log[x]]: 0) - -static inline u32 upr(u32 x, int n) -{ - return (x << 8 * n) | (x >> (32 - 8 * n)); -} - -static inline u8 bval(u32 x, int n) -{ - return x >> 8 * n; -} - -/* The forward and inverse affine transformations used in the S-box */ -#define fwd_affine(x) \ - (w = (u32)x, w ^= (w<<1)^(w<<2)^(w<<3)^(w<<4), 0x63^(u8)(w^(w>>8))) - -#define inv_affine(x) \ - (w = (u32)x, w = (w<<1)^(w<<3)^(w<<6), 0x05^(u8)(w^(w>>8))) - -static u32 rcon_tab[RC_LENGTH]; - -u32 ft_tab[4][256]; -u32 fl_tab[4][256]; -static u32 im_tab[4][256]; -u32 il_tab[4][256]; -u32 it_tab[4][256]; - -static void gen_tabs(void) -{ - u32 i, w; - u8 pow[512], log[256]; - - /* - * log and power tables for GF(2^8) finite field with - * WPOLY as modular polynomial - the simplest primitive - * root is 0x03, used here to generate the tables. - */ - i = 0; w = 1; - - do { - pow[i] = (u8)w; - pow[i + 255] = (u8)w; - log[w] = (u8)i++; - w ^= (w << 1) ^ (w & 0x80 ? WPOLY : 0); - } while (w != 1); - - for(i = 0, w = 1; i < RC_LENGTH; ++i) { - rcon_tab[i] = bytes2word(w, 0, 0, 0); - w = f2(w); - } - - for(i = 0; i < 256; ++i) { - u8 b; - - b = fwd_affine(fi((u8)i)); - w = bytes2word(f2(b), b, b, f3(b)); - - /* tables for a normal encryption round */ - ft_tab[0][i] = w; - ft_tab[1][i] = upr(w, 1); - ft_tab[2][i] = upr(w, 2); - ft_tab[3][i] = upr(w, 3); - w = bytes2word(b, 0, 0, 0); - - /* - * tables for last encryption round - * (may also be used in the key schedule) - */ - fl_tab[0][i] = w; - fl_tab[1][i] = upr(w, 1); - fl_tab[2][i] = upr(w, 2); - fl_tab[3][i] = upr(w, 3); - - b = fi(inv_affine((u8)i)); - w = bytes2word(fe(b), f9(b), fd(b), fb(b)); - - /* tables for the inverse mix column operation */ - im_tab[0][b] = w; - im_tab[1][b] = upr(w, 1); - im_tab[2][b] = upr(w, 2); - im_tab[3][b] = upr(w, 3); - - /* tables for a normal decryption round */ - it_tab[0][i] = w; - it_tab[1][i] = upr(w,1); - it_tab[2][i] = upr(w,2); - it_tab[3][i] = upr(w,3); - - w = bytes2word(b, 0, 0, 0); - - /* tables for last decryption round */ - il_tab[0][i] = w; - il_tab[1][i] = upr(w,1); - il_tab[2][i] = upr(w,2); - il_tab[3][i] = upr(w,3); - } -} - -#define four_tables(x,tab,vf,rf,c) \ -( tab[0][bval(vf(x,0,c),rf(0,c))] ^ \ - tab[1][bval(vf(x,1,c),rf(1,c))] ^ \ - tab[2][bval(vf(x,2,c),rf(2,c))] ^ \ - tab[3][bval(vf(x,3,c),rf(3,c))] \ -) - -#define vf1(x,r,c) (x) -#define rf1(r,c) (r) -#define rf2(r,c) ((r-c)&3) - -#define inv_mcol(x) four_tables(x,im_tab,vf1,rf1,0) -#define ls_box(x,c) four_tables(x,fl_tab,vf1,rf2,c) - -#define ff(x) inv_mcol(x) - -#define ke4(k,i) \ -{ \ - k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ rcon_tab[i]; \ - k[4*(i)+5] = ss[1] ^= ss[0]; \ - k[4*(i)+6] = ss[2] ^= ss[1]; \ - k[4*(i)+7] = ss[3] ^= ss[2]; \ -} - -#define kel4(k,i) \ -{ \ - k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ rcon_tab[i]; \ - k[4*(i)+5] = ss[1] ^= ss[0]; \ - k[4*(i)+6] = ss[2] ^= ss[1]; k[4*(i)+7] = ss[3] ^= ss[2]; \ -} - -#define ke6(k,i) \ -{ \ - k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i]; \ - k[6*(i)+ 7] = ss[1] ^= ss[0]; \ - k[6*(i)+ 8] = ss[2] ^= ss[1]; \ - k[6*(i)+ 9] = ss[3] ^= ss[2]; \ - k[6*(i)+10] = ss[4] ^= ss[3]; \ - k[6*(i)+11] = ss[5] ^= ss[4]; \ -} - -#define kel6(k,i) \ -{ \ - k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i]; \ - k[6*(i)+ 7] = ss[1] ^= ss[0]; \ - k[6*(i)+ 8] = ss[2] ^= ss[1]; \ - k[6*(i)+ 9] = ss[3] ^= ss[2]; \ -} - -#define ke8(k,i) \ -{ \ - k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i]; \ - k[8*(i)+ 9] = ss[1] ^= ss[0]; \ - k[8*(i)+10] = ss[2] ^= ss[1]; \ - k[8*(i)+11] = ss[3] ^= ss[2]; \ - k[8*(i)+12] = ss[4] ^= ls_box(ss[3],0); \ - k[8*(i)+13] = ss[5] ^= ss[4]; \ - k[8*(i)+14] = ss[6] ^= ss[5]; \ - k[8*(i)+15] = ss[7] ^= ss[6]; \ -} - -#define kel8(k,i) \ -{ \ - k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i]; \ - k[8*(i)+ 9] = ss[1] ^= ss[0]; \ - k[8*(i)+10] = ss[2] ^= ss[1]; \ - k[8*(i)+11] = ss[3] ^= ss[2]; \ -} - -#define kdf4(k,i) \ -{ \ - ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3]; \ - ss[1] = ss[1] ^ ss[3]; \ - ss[2] = ss[2] ^ ss[3]; \ - ss[3] = ss[3]; \ - ss[4] = ls_box(ss[(i+3) % 4], 3) ^ rcon_tab[i]; \ - ss[i % 4] ^= ss[4]; \ - ss[4] ^= k[4*(i)]; \ - k[4*(i)+4] = ff(ss[4]); \ - ss[4] ^= k[4*(i)+1]; \ - k[4*(i)+5] = ff(ss[4]); \ - ss[4] ^= k[4*(i)+2]; \ - k[4*(i)+6] = ff(ss[4]); \ - ss[4] ^= k[4*(i)+3]; \ - k[4*(i)+7] = ff(ss[4]); \ -} - -#define kd4(k,i) \ -{ \ - ss[4] = ls_box(ss[(i+3) % 4], 3) ^ rcon_tab[i]; \ - ss[i % 4] ^= ss[4]; \ - ss[4] = ff(ss[4]); \ - k[4*(i)+4] = ss[4] ^= k[4*(i)]; \ - k[4*(i)+5] = ss[4] ^= k[4*(i)+1]; \ - k[4*(i)+6] = ss[4] ^= k[4*(i)+2]; \ - k[4*(i)+7] = ss[4] ^= k[4*(i)+3]; \ -} - -#define kdl4(k,i) \ -{ \ - ss[4] = ls_box(ss[(i+3) % 4], 3) ^ rcon_tab[i]; \ - ss[i % 4] ^= ss[4]; \ - k[4*(i)+4] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3]; \ - k[4*(i)+5] = ss[1] ^ ss[3]; \ - k[4*(i)+6] = ss[0]; \ - k[4*(i)+7] = ss[1]; \ -} - -#define kdf6(k,i) \ -{ \ - ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i]; \ - k[6*(i)+ 6] = ff(ss[0]); \ - ss[1] ^= ss[0]; \ - k[6*(i)+ 7] = ff(ss[1]); \ - ss[2] ^= ss[1]; \ - k[6*(i)+ 8] = ff(ss[2]); \ - ss[3] ^= ss[2]; \ - k[6*(i)+ 9] = ff(ss[3]); \ - ss[4] ^= ss[3]; \ - k[6*(i)+10] = ff(ss[4]); \ - ss[5] ^= ss[4]; \ - k[6*(i)+11] = ff(ss[5]); \ -} - -#define kd6(k,i) \ -{ \ - ss[6] = ls_box(ss[5],3) ^ rcon_tab[i]; \ - ss[0] ^= ss[6]; ss[6] = ff(ss[6]); \ - k[6*(i)+ 6] = ss[6] ^= k[6*(i)]; \ - ss[1] ^= ss[0]; \ - k[6*(i)+ 7] = ss[6] ^= k[6*(i)+ 1]; \ - ss[2] ^= ss[1]; \ - k[6*(i)+ 8] = ss[6] ^= k[6*(i)+ 2]; \ - ss[3] ^= ss[2]; \ - k[6*(i)+ 9] = ss[6] ^= k[6*(i)+ 3]; \ - ss[4] ^= ss[3]; \ - k[6*(i)+10] = ss[6] ^= k[6*(i)+ 4]; \ - ss[5] ^= ss[4]; \ - k[6*(i)+11] = ss[6] ^= k[6*(i)+ 5]; \ -} - -#define kdl6(k,i) \ -{ \ - ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i]; \ - k[6*(i)+ 6] = ss[0]; \ - ss[1] ^= ss[0]; \ - k[6*(i)+ 7] = ss[1]; \ - ss[2] ^= ss[1]; \ - k[6*(i)+ 8] = ss[2]; \ - ss[3] ^= ss[2]; \ - k[6*(i)+ 9] = ss[3]; \ -} - -#define kdf8(k,i) \ -{ \ - ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i]; \ - k[8*(i)+ 8] = ff(ss[0]); \ - ss[1] ^= ss[0]; \ - k[8*(i)+ 9] = ff(ss[1]); \ - ss[2] ^= ss[1]; \ - k[8*(i)+10] = ff(ss[2]); \ - ss[3] ^= ss[2]; \ - k[8*(i)+11] = ff(ss[3]); \ - ss[4] ^= ls_box(ss[3],0); \ - k[8*(i)+12] = ff(ss[4]); \ - ss[5] ^= ss[4]; \ - k[8*(i)+13] = ff(ss[5]); \ - ss[6] ^= ss[5]; \ - k[8*(i)+14] = ff(ss[6]); \ - ss[7] ^= ss[6]; \ - k[8*(i)+15] = ff(ss[7]); \ -} - -#define kd8(k,i) \ -{ \ - u32 __g = ls_box(ss[7],3) ^ rcon_tab[i]; \ - ss[0] ^= __g; \ - __g = ff(__g); \ - k[8*(i)+ 8] = __g ^= k[8*(i)]; \ - ss[1] ^= ss[0]; \ - k[8*(i)+ 9] = __g ^= k[8*(i)+ 1]; \ - ss[2] ^= ss[1]; \ - k[8*(i)+10] = __g ^= k[8*(i)+ 2]; \ - ss[3] ^= ss[2]; \ - k[8*(i)+11] = __g ^= k[8*(i)+ 3]; \ - __g = ls_box(ss[3],0); \ - ss[4] ^= __g; \ - __g = ff(__g); \ - k[8*(i)+12] = __g ^= k[8*(i)+ 4]; \ - ss[5] ^= ss[4]; \ - k[8*(i)+13] = __g ^= k[8*(i)+ 5]; \ - ss[6] ^= ss[5]; \ - k[8*(i)+14] = __g ^= k[8*(i)+ 6]; \ - ss[7] ^= ss[6]; \ - k[8*(i)+15] = __g ^= k[8*(i)+ 7]; \ -} - -#define kdl8(k,i) \ -{ \ - ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i]; \ - k[8*(i)+ 8] = ss[0]; \ - ss[1] ^= ss[0]; \ - k[8*(i)+ 9] = ss[1]; \ - ss[2] ^= ss[1]; \ - k[8*(i)+10] = ss[2]; \ - ss[3] ^= ss[2]; \ - k[8*(i)+11] = ss[3]; \ -} - -static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, - unsigned int key_len) -{ - int i; - u32 ss[8]; - struct aes_ctx *ctx = crypto_tfm_ctx(tfm); - const __le32 *key = (const __le32 *)in_key; - u32 *flags = &tfm->crt_flags; - - /* encryption schedule */ - - ctx->ekey[0] = ss[0] = le32_to_cpu(key[0]); - ctx->ekey[1] = ss[1] = le32_to_cpu(key[1]); - ctx->ekey[2] = ss[2] = le32_to_cpu(key[2]); - ctx->ekey[3] = ss[3] = le32_to_cpu(key[3]); - - switch(key_len) { - case 16: - for (i = 0; i < 9; i++) - ke4(ctx->ekey, i); - kel4(ctx->ekey, 9); - ctx->rounds = 10; - break; - - case 24: - ctx->ekey[4] = ss[4] = le32_to_cpu(key[4]); - ctx->ekey[5] = ss[5] = le32_to_cpu(key[5]); - for (i = 0; i < 7; i++) - ke6(ctx->ekey, i); - kel6(ctx->ekey, 7); - ctx->rounds = 12; - break; - - case 32: - ctx->ekey[4] = ss[4] = le32_to_cpu(key[4]); - ctx->ekey[5] = ss[5] = le32_to_cpu(key[5]); - ctx->ekey[6] = ss[6] = le32_to_cpu(key[6]); - ctx->ekey[7] = ss[7] = le32_to_cpu(key[7]); - for (i = 0; i < 6; i++) - ke8(ctx->ekey, i); - kel8(ctx->ekey, 6); - ctx->rounds = 14; - break; - - default: - *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; - return -EINVAL; - } - - /* decryption schedule */ - - ctx->dkey[0] = ss[0] = le32_to_cpu(key[0]); - ctx->dkey[1] = ss[1] = le32_to_cpu(key[1]); - ctx->dkey[2] = ss[2] = le32_to_cpu(key[2]); - ctx->dkey[3] = ss[3] = le32_to_cpu(key[3]); - - switch (key_len) { - case 16: - kdf4(ctx->dkey, 0); - for (i = 1; i < 9; i++) - kd4(ctx->dkey, i); - kdl4(ctx->dkey, 9); - break; - - case 24: - ctx->dkey[4] = ff(ss[4] = le32_to_cpu(key[4])); - ctx->dkey[5] = ff(ss[5] = le32_to_cpu(key[5])); - kdf6(ctx->dkey, 0); - for (i = 1; i < 7; i++) - kd6(ctx->dkey, i); - kdl6(ctx->dkey, 7); - break; - - case 32: - ctx->dkey[4] = ff(ss[4] = le32_to_cpu(key[4])); - ctx->dkey[5] = ff(ss[5] = le32_to_cpu(key[5])); - ctx->dkey[6] = ff(ss[6] = le32_to_cpu(key[6])); - ctx->dkey[7] = ff(ss[7] = le32_to_cpu(key[7])); - kdf8(ctx->dkey, 0); - for (i = 1; i < 6; i++) - kd8(ctx->dkey, i); - kdl8(ctx->dkey, 6); - break; - } - return 0; -} - -static void aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) -{ - aes_enc_blk(tfm, dst, src); -} - -static void aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) -{ - aes_dec_blk(tfm, dst, src); -} - -static struct crypto_alg aes_alg = { - .cra_name = "aes", - .cra_driver_name = "aes-i586", - .cra_priority = 200, - .cra_flags = CRYPTO_ALG_TYPE_CIPHER, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct aes_ctx), - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), - .cra_u = { - .cipher = { - .cia_min_keysize = AES_MIN_KEY_SIZE, - .cia_max_keysize = AES_MAX_KEY_SIZE, - .cia_setkey = aes_set_key, - .cia_encrypt = aes_encrypt, - .cia_decrypt = aes_decrypt - } - } -}; - -static int __init aes_init(void) -{ - gen_tabs(); - return crypto_register_alg(&aes_alg); -} - -static void __exit aes_fini(void) -{ - crypto_unregister_alg(&aes_alg); -} - -module_init(aes_init); -module_exit(aes_fini); - -MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm, i586 asm optimized"); -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_AUTHOR("Fruhwirth Clemens, James Morris, Brian Gladman, Adam Richter"); -MODULE_ALIAS("aes"); diff --git a/arch/x86/crypto/aes_64.c b/arch/x86/crypto/aes_64.c deleted file mode 100644 index 5cdb13ea5cc2..000000000000 --- a/arch/x86/crypto/aes_64.c +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Cryptographic API. - * - * AES Cipher Algorithm. - * - * Based on Brian Gladman's code. - * - * Linux developers: - * Alexander Kjeldaas <astor@fast.no> - * Herbert Valerio Riedel <hvr@hvrlab.org> - * Kyle McMartin <kyle@debian.org> - * Adam J. Richter <adam@yggdrasil.com> (conversion to 2.5 API). - * Andreas Steinmetz <ast@domdv.de> (adapted to x86_64 assembler) - * - * 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. - * - * --------------------------------------------------------------------------- - * Copyright (c) 2002, Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK. - * All rights reserved. - * - * LICENSE TERMS - * - * The free distribution and use of this software in both source and binary - * form is allowed (with or without changes) provided that: - * - * 1. distributions of this source code include the above copyright - * notice, this list of conditions and the following disclaimer; - * - * 2. distributions in binary form include the above copyright - * notice, this list of conditions and the following disclaimer - * in the documentation and/or other associated materials; - * - * 3. the copyright holder's name is not used to endorse products - * built using this software without specific written permission. - * - * ALTERNATIVELY, provided that this notice is retained in full, this product - * may be distributed under the terms of the GNU General Public License (GPL), - * in which case the provisions of the GPL apply INSTEAD OF those given above. - * - * DISCLAIMER - * - * This software is provided 'as is' with no explicit or implied warranties - * in respect of its properties, including, but not limited to, correctness - * and/or fitness for purpose. - * --------------------------------------------------------------------------- - */ - -/* Some changes from the Gladman version: - s/RIJNDAEL(e_key)/E_KEY/g - s/RIJNDAEL(d_key)/D_KEY/g -*/ - -#include <asm/byteorder.h> -#include <linux/bitops.h> -#include <linux/crypto.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/types.h> - -#define AES_MIN_KEY_SIZE 16 -#define AES_MAX_KEY_SIZE 32 - -#define AES_BLOCK_SIZE 16 - -/* - * #define byte(x, nr) ((unsigned char)((x) >> (nr*8))) - */ -static inline u8 byte(const u32 x, const unsigned n) -{ - return x >> (n << 3); -} - -struct aes_ctx -{ - u32 key_length; - u32 buf[120]; -}; - -#define E_KEY (&ctx->buf[0]) -#define D_KEY (&ctx->buf[60]) - -static u8 pow_tab[256] __initdata; -static u8 log_tab[256] __initdata; -static u8 sbx_tab[256] __initdata; -static u8 isb_tab[256] __initdata; -static u32 rco_tab[10]; -u32 aes_ft_tab[4][256]; -u32 aes_it_tab[4][256]; - -u32 aes_fl_tab[4][256]; -u32 aes_il_tab[4][256]; - -static inline u8 f_mult(u8 a, u8 b) -{ - u8 aa = log_tab[a], cc = aa + log_tab[b]; - - return pow_tab[cc + (cc < aa ? 1 : 0)]; -} - -#define ff_mult(a, b) (a && b ? f_mult(a, b) : 0) - -#define ls_box(x) \ - (aes_fl_tab[0][byte(x, 0)] ^ \ - aes_fl_tab[1][byte(x, 1)] ^ \ - aes_fl_tab[2][byte(x, 2)] ^ \ - aes_fl_tab[3][byte(x, 3)]) - -static void __init gen_tabs(void) -{ - u32 i, t; - u8 p, q; - - /* log and power tables for GF(2**8) finite field with - 0x011b as modular polynomial - the simplest primitive - root is 0x03, used here to generate the tables */ - - for (i = 0, p = 1; i < 256; ++i) { - pow_tab[i] = (u8)p; - log_tab[p] = (u8)i; - - p ^= (p << 1) ^ (p & 0x80 ? 0x01b : 0); - } - - log_tab[1] = 0; - - for (i = 0, p = 1; i < 10; ++i) { - rco_tab[i] = p; - - p = (p << 1) ^ (p & 0x80 ? 0x01b : 0); - } - - for (i = 0; i < 256; ++i) { - p = (i ? pow_tab[255 - log_tab[i]] : 0); - q = ((p >> 7) | (p << 1)) ^ ((p >> 6) | (p << 2)); - p ^= 0x63 ^ q ^ ((q >> 6) | (q << 2)); - sbx_tab[i] = p; - isb_tab[p] = (u8)i; - } - - for (i = 0; i < 256; ++i) { - p = sbx_tab[i]; - - t = p; - aes_fl_tab[0][i] = t; - aes_fl_tab[1][i] = rol32(t, 8); - aes_fl_tab[2][i] = rol32(t, 16); - aes_fl_tab[3][i] = rol32(t, 24); - - t = ((u32)ff_mult(2, p)) | - ((u32)p << 8) | - ((u32)p << 16) | ((u32)ff_mult(3, p) << 24); - - aes_ft_tab[0][i] = t; - aes_ft_tab[1][i] = rol32(t, 8); - aes_ft_tab[2][i] = rol32(t, 16); - aes_ft_tab[3][i] = rol32(t, 24); - - p = isb_tab[i]; - - t = p; - aes_il_tab[0][i] = t; - aes_il_tab[1][i] = rol32(t, 8); - aes_il_tab[2][i] = rol32(t, 16); - aes_il_tab[3][i] = rol32(t, 24); - - t = ((u32)ff_mult(14, p)) | - ((u32)ff_mult(9, p) << 8) | - ((u32)ff_mult(13, p) << 16) | - ((u32)ff_mult(11, p) << 24); - - aes_it_tab[0][i] = t; - aes_it_tab[1][i] = rol32(t, 8); - aes_it_tab[2][i] = rol32(t, 16); - aes_it_tab[3][i] = rol32(t, 24); - } -} - -#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b) - -#define imix_col(y, x) \ - u = star_x(x); \ - v = star_x(u); \ - w = star_x(v); \ - t = w ^ (x); \ - (y) = u ^ v ^ w; \ - (y) ^= ror32(u ^ t, 8) ^ \ - ror32(v ^ t, 16) ^ \ - ror32(t, 24) - -/* initialise the key schedule from the user supplied key */ - -#define loop4(i) \ -{ \ - t = ror32(t, 8); t = ls_box(t) ^ rco_tab[i]; \ - t ^= E_KEY[4 * i]; E_KEY[4 * i + 4] = t; \ - t ^= E_KEY[4 * i + 1]; E_KEY[4 * i + 5] = t; \ - t ^= E_KEY[4 * i + 2]; E_KEY[4 * i + 6] = t; \ - t ^= E_KEY[4 * i + 3]; E_KEY[4 * i + 7] = t; \ -} - -#define loop6(i) \ -{ \ - t = ror32(t, 8); t = ls_box(t) ^ rco_tab[i]; \ - t ^= E_KEY[6 * i]; E_KEY[6 * i + 6] = t; \ - t ^= E_KEY[6 * i + 1]; E_KEY[6 * i + 7] = t; \ - t ^= E_KEY[6 * i + 2]; E_KEY[6 * i + 8] = t; \ - t ^= E_KEY[6 * i + 3]; E_KEY[6 * i + 9] = t; \ - t ^= E_KEY[6 * i + 4]; E_KEY[6 * i + 10] = t; \ - t ^= E_KEY[6 * i + 5]; E_KEY[6 * i + 11] = t; \ -} - -#define loop8(i) \ -{ \ - t = ror32(t, 8); ; t = ls_box(t) ^ rco_tab[i]; \ - t ^= E_KEY[8 * i]; E_KEY[8 * i + 8] = t; \ - t ^= E_KEY[8 * i + 1]; E_KEY[8 * i + 9] = t; \ - t ^= E_KEY[8 * i + 2]; E_KEY[8 * i + 10] = t; \ - t ^= E_KEY[8 * i + 3]; E_KEY[8 * i + 11] = t; \ - t = E_KEY[8 * i + 4] ^ ls_box(t); \ - E_KEY[8 * i + 12] = t; \ - t ^= E_KEY[8 * i + 5]; E_KEY[8 * i + 13] = t; \ - t ^= E_KEY[8 * i + 6]; E_KEY[8 * i + 14] = t; \ - t ^= E_KEY[8 * i + 7]; E_KEY[8 * i + 15] = t; \ -} - -static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, - unsigned int key_len) -{ - struct aes_ctx *ctx = crypto_tfm_ctx(tfm); - const __le32 *key = (const __le32 *)in_key; - u32 *flags = &tfm->crt_flags; - u32 i, j, t, u, v, w; - - if (key_len % 8) { - *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; - return -EINVAL; - } - - ctx->key_length = key_len; - - D_KEY[key_len + 24] = E_KEY[0] = le32_to_cpu(key[0]); - D_KEY[key_len + 25] = E_KEY[1] = le32_to_cpu(key[1]); - D_KEY[key_len + 26] = E_KEY[2] = le32_to_cpu(key[2]); - D_KEY[key_len + 27] = E_KEY[3] = le32_to_cpu(key[3]); - - switch (key_len) { - case 16: - t = E_KEY[3]; - for (i = 0; i < 10; ++i) - loop4(i); - break; - - case 24: - E_KEY[4] = le32_to_cpu(key[4]); - t = E_KEY[5] = le32_to_cpu(key[5]); - for (i = 0; i < 8; ++i) - loop6 (i); - break; - - case 32: - E_KEY[4] = le32_to_cpu(key[4]); - E_KEY[5] = le32_to_cpu(key[5]); - E_KEY[6] = le32_to_cpu(key[6]); - t = E_KEY[7] = le32_to_cpu(key[7]); - for (i = 0; i < 7; ++i) - loop8(i); - break; - } - - D_KEY[0] = E_KEY[key_len + 24]; - D_KEY[1] = E_KEY[key_len + 25]; - D_KEY[2] = E_KEY[key_len + 26]; - D_KEY[3] = E_KEY[key_len + 27]; - - for (i = 4; i < key_len + 24; ++i) { - j = key_len + 24 - (i & ~3) + (i & 3); - imix_col(D_KEY[j], E_KEY[i]); - } - - return 0; -} - -asmlinkage void aes_enc_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in); -asmlinkage void aes_dec_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in); - -static void aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) -{ - aes_enc_blk(tfm, dst, src); -} - -static void aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) -{ - aes_dec_blk(tfm, dst, src); -} - -static struct crypto_alg aes_alg = { - .cra_name = "aes", - .cra_driver_name = "aes-x86_64", - .cra_priority = 200, - .cra_flags = CRYPTO_ALG_TYPE_CIPHER, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct aes_ctx), - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), - .cra_u = { - .cipher = { - .cia_min_keysize = AES_MIN_KEY_SIZE, - .cia_max_keysize = AES_MAX_KEY_SIZE, - .cia_setkey = aes_set_key, - .cia_encrypt = aes_encrypt, - .cia_decrypt = aes_decrypt - } - } -}; - -static int __init aes_init(void) -{ - gen_tabs(); - return crypto_register_alg(&aes_alg); -} - -static void __exit aes_fini(void) -{ - crypto_unregister_alg(&aes_alg); -} - -module_init(aes_init); -module_exit(aes_fini); - -MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("aes"); diff --git a/arch/x86/crypto/aes_glue.c b/arch/x86/crypto/aes_glue.c new file mode 100644 index 000000000000..71f457827116 --- /dev/null +++ b/arch/x86/crypto/aes_glue.c @@ -0,0 +1,57 @@ +/* + * Glue Code for the asm optimized version of the AES Cipher Algorithm + * + */ + +#include <crypto/aes.h> + +asmlinkage void aes_enc_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in); +asmlinkage void aes_dec_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in); + +static void aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +{ + aes_enc_blk(tfm, dst, src); +} + +static void aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +{ + aes_dec_blk(tfm, dst, src); +} + +static struct crypto_alg aes_alg = { + .cra_name = "aes", + .cra_driver_name = "aes-asm", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypto_aes_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = AES_MIN_KEY_SIZE, + .cia_max_keysize = AES_MAX_KEY_SIZE, + .cia_setkey = crypto_aes_set_key, + .cia_encrypt = aes_encrypt, + .cia_decrypt = aes_decrypt + } + } +}; + +static int __init aes_init(void) +{ + return crypto_register_alg(&aes_alg); +} + +static void __exit aes_fini(void) +{ + crypto_unregister_alg(&aes_alg); +} + +module_init(aes_init); +module_exit(aes_fini); + +MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm, asm optimized"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("aes"); +MODULE_ALIAS("aes-asm"); diff --git a/arch/x86/crypto/salsa20-i586-asm_32.S b/arch/x86/crypto/salsa20-i586-asm_32.S new file mode 100644 index 000000000000..72eb306680b2 --- /dev/null +++ b/arch/x86/crypto/salsa20-i586-asm_32.S @@ -0,0 +1,1114 @@ +# salsa20_pm.s version 20051229 +# D. J. Bernstein +# Public domain. + +# enter ECRYPT_encrypt_bytes +.text +.p2align 5 +.globl ECRYPT_encrypt_bytes +ECRYPT_encrypt_bytes: + mov %esp,%eax + and $31,%eax + add $256,%eax + sub %eax,%esp + # eax_stack = eax + movl %eax,80(%esp) + # ebx_stack = ebx + movl %ebx,84(%esp) + # esi_stack = esi + movl %esi,88(%esp) + # edi_stack = edi + movl %edi,92(%esp) + # ebp_stack = ebp + movl %ebp,96(%esp) + # x = arg1 + movl 4(%esp,%eax),%edx + # m = arg2 + movl 8(%esp,%eax),%esi + # out = arg3 + movl 12(%esp,%eax),%edi + # bytes = arg4 + movl 16(%esp,%eax),%ebx + # bytes -= 0 + sub $0,%ebx + # goto done if unsigned<= + jbe ._done +._start: + # in0 = *(uint32 *) (x + 0) + movl 0(%edx),%eax + # in1 = *(uint32 *) (x + 4) + movl 4(%edx),%ecx + # in2 = *(uint32 *) (x + 8) + movl 8(%edx),%ebp + # j0 = in0 + movl %eax,164(%esp) + # in3 = *(uint32 *) (x + 12) + movl 12(%edx),%eax + # j1 = in1 + movl %ecx,168(%esp) + # in4 = *(uint32 *) (x + 16) + movl 16(%edx),%ecx + # j2 = in2 + movl %ebp,172(%esp) + # in5 = *(uint32 *) (x + 20) + movl 20(%edx),%ebp + # j3 = in3 + movl %eax,176(%esp) + # in6 = *(uint32 *) (x + 24) + movl 24(%edx),%eax + # j4 = in4 + movl %ecx,180(%esp) + # in7 = *(uint32 *) (x + 28) + movl 28(%edx),%ecx + # j5 = in5 + movl %ebp,184(%esp) + # in8 = *(uint32 *) (x + 32) + movl 32(%edx),%ebp + # j6 = in6 + movl %eax,188(%esp) + # in9 = *(uint32 *) (x + 36) + movl 36(%edx),%eax + # j7 = in7 + movl %ecx,192(%esp) + # in10 = *(uint32 *) (x + 40) + movl 40(%edx),%ecx + # j8 = in8 + movl %ebp,196(%esp) + # in11 = *(uint32 *) (x + 44) + movl 44(%edx),%ebp + # j9 = in9 + movl %eax,200(%esp) + # in12 = *(uint32 *) (x + 48) + movl 48(%edx),%eax + # j10 = in10 + movl %ecx,204(%esp) + # in13 = *(uint32 *) (x + 52) + movl 52(%edx),%ecx + # j11 = in11 + movl %ebp,208(%esp) + # in14 = *(uint32 *) (x + 56) + movl 56(%edx),%ebp + # j12 = in12 + movl %eax,212(%esp) + # in15 = *(uint32 *) (x + 60) + movl 60(%edx),%eax + # j13 = in13 + movl %ecx,216(%esp) + # j14 = in14 + movl %ebp,220(%esp) + # j15 = in15 + movl %eax,224(%esp) + # x_backup = x + movl %edx,64(%esp) +._bytesatleast1: + # bytes - 64 + cmp $64,%ebx + # goto nocopy if unsigned>= + jae ._nocopy + # ctarget = out + movl %edi,228(%esp) + # out = &tmp + leal 0(%esp),%edi + # i = bytes + mov %ebx,%ecx + # while (i) { *out++ = *m++; --i } + rep movsb + # out = &tmp + leal 0(%esp),%edi + # m = &tmp + leal 0(%esp),%esi +._nocopy: + # out_backup = out + movl %edi,72(%esp) + # m_backup = m + movl %esi,68(%esp) + # bytes_backup = bytes + movl %ebx,76(%esp) + # in0 = j0 + movl 164(%esp),%eax + # in1 = j1 + movl 168(%esp),%ecx + # in2 = j2 + movl 172(%esp),%edx + # in3 = j3 + movl 176(%esp),%ebx + # x0 = in0 + movl %eax,100(%esp) + # x1 = in1 + movl %ecx,104(%esp) + # x2 = in2 + movl %edx,108(%esp) + # x3 = in3 + movl %ebx,112(%esp) + # in4 = j4 + movl 180(%esp),%eax + # in5 = j5 + movl 184(%esp),%ecx + # in6 = j6 + movl 188(%esp),%edx + # in7 = j7 + movl 192(%esp),%ebx + # x4 = in4 + movl %eax,116(%esp) + # x5 = in5 + movl %ecx,120(%esp) + # x6 = in6 + movl %edx,124(%esp) + # x7 = in7 + movl %ebx,128(%esp) + # in8 = j8 + movl 196(%esp),%eax + # in9 = j9 + movl 200(%esp),%ecx + # in10 = j10 + movl 204(%esp),%edx + # in11 = j11 + movl 208(%esp),%ebx + # x8 = in8 + movl %eax,132(%esp) + # x9 = in9 + movl %ecx,136(%esp) + # x10 = in10 + movl %edx,140(%esp) + # x11 = in11 + movl %ebx,144(%esp) + # in12 = j12 + movl 212(%esp),%eax + # in13 = j13 + movl 216(%esp),%ecx + # in14 = j14 + movl 220(%esp),%edx + # in15 = j15 + movl 224(%esp),%ebx + # x12 = in12 + movl %eax,148(%esp) + # x13 = in13 + movl %ecx,152(%esp) + # x14 = in14 + movl %edx,156(%esp) + # x15 = in15 + movl %ebx,160(%esp) + # i = 20 + mov $20,%ebp + # p = x0 + movl 100(%esp),%eax + # s = x5 + movl 120(%esp),%ecx + # t = x10 + movl 140(%esp),%edx + # w = x15 + movl 160(%esp),%ebx +._mainloop: + # x0 = p + movl %eax,100(%esp) + # x10 = t + movl %edx,140(%esp) + # p += x12 + addl 148(%esp),%eax + # x5 = s + movl %ecx,120(%esp) + # t += x6 + addl 124(%esp),%edx + # x15 = w + movl %ebx,160(%esp) + # r = x1 + movl 104(%esp),%esi + # r += s + add %ecx,%esi + # v = x11 + movl 144(%esp),%edi + # v += w + add %ebx,%edi + # p <<<= 7 + rol $7,%eax + # p ^= x4 + xorl 116(%esp),%eax + # t <<<= 7 + rol $7,%edx + # t ^= x14 + xorl 156(%esp),%edx + # r <<<= 7 + rol $7,%esi + # r ^= x9 + xorl 136(%esp),%esi + # v <<<= 7 + rol $7,%edi + # v ^= x3 + xorl 112(%esp),%edi + # x4 = p + movl %eax,116(%esp) + # x14 = t + movl %edx,156(%esp) + # p += x0 + addl 100(%esp),%eax + # x9 = r + movl %esi,136(%esp) + # t += x10 + addl 140(%esp),%edx + # x3 = v + movl %edi,112(%esp) + # p <<<= 9 + rol $9,%eax + # p ^= x8 + xorl 132(%esp),%eax + # t <<<= 9 + rol $9,%edx + # t ^= x2 + xorl 108(%esp),%edx + # s += r + add %esi,%ecx + # s <<<= 9 + rol $9,%ecx + # s ^= x13 + xorl 152(%esp),%ecx + # w += v + add %edi,%ebx + # w <<<= 9 + rol $9,%ebx + # w ^= x7 + xorl 128(%esp),%ebx + # x8 = p + movl %eax,132(%esp) + # x2 = t + movl %edx,108(%esp) + # p += x4 + addl 116(%esp),%eax + # x13 = s + movl %ecx,152(%esp) + # t += x14 + addl 156(%esp),%edx + # x7 = w + movl %ebx,128(%esp) + # p <<<= 13 + rol $13,%eax + # p ^= x12 + xorl 148(%esp),%eax + # t <<<= 13 + rol $13,%edx + # t ^= x6 + xorl 124(%esp),%edx + # r += s + add %ecx,%esi + # r <<<= 13 + rol $13,%esi + # r ^= x1 + xorl 104(%esp),%esi + # v += w + add %ebx,%edi + # v <<<= 13 + rol $13,%edi + # v ^= x11 + xorl 144(%esp),%edi + # x12 = p + movl %eax,148(%esp) + # x6 = t + movl %edx,124(%esp) + # p += x8 + addl 132(%esp),%eax + # x1 = r + movl %esi,104(%esp) + # t += x2 + addl 108(%esp),%edx + # x11 = v + movl %edi,144(%esp) + # p <<<= 18 + rol $18,%eax + # p ^= x0 + xorl 100(%esp),%eax + # t <<<= 18 + rol $18,%edx + # t ^= x10 + xorl 140(%esp),%edx + # s += r + add %esi,%ecx + # s <<<= 18 + rol $18,%ecx + # s ^= x5 + xorl 120(%esp),%ecx + # w += v + add %edi,%ebx + # w <<<= 18 + rol $18,%ebx + # w ^= x15 + xorl 160(%esp),%ebx + # x0 = p + movl %eax,100(%esp) + # x10 = t + movl %edx,140(%esp) + # p += x3 + addl 112(%esp),%eax + # p <<<= 7 + rol $7,%eax + # x5 = s + movl %ecx,120(%esp) + # t += x9 + addl 136(%esp),%edx + # x15 = w + movl %ebx,160(%esp) + # r = x4 + movl 116(%esp),%esi + # r += s + add %ecx,%esi + # v = x14 + movl 156(%esp),%edi + # v += w + add %ebx,%edi + # p ^= x1 + xorl 104(%esp),%eax + # t <<<= 7 + rol $7,%edx + # t ^= x11 + xorl 144(%esp),%edx + # r <<<= 7 + rol $7,%esi + # r ^= x6 + xorl 124(%esp),%esi + # v <<<= 7 + rol $7,%edi + # v ^= x12 + xorl 148(%esp),%edi + # x1 = p + movl %eax,104(%esp) + # x11 = t + movl %edx,144(%esp) + # p += x0 + addl 100(%esp),%eax + # x6 = r + movl %esi,124(%esp) + # t += x10 + addl 140(%esp),%edx + # x12 = v + movl %edi,148(%esp) + # p <<<= 9 + rol $9,%eax + # p ^= x2 + xorl 108(%esp),%eax + # t <<<= 9 + rol $9,%edx + # t ^= x8 + xorl 132(%esp),%edx + # s += r + add %esi,%ecx + # s <<<= 9 + rol $9,%ecx + # s ^= x7 + xorl 128(%esp),%ecx + # w += v + add %edi,%ebx + # w <<<= 9 + rol $9,%ebx + # w ^= x13 + xorl 152(%esp),%ebx + # x2 = p + movl %eax,108(%esp) + # x8 = t + movl %edx,132(%esp) + # p += x1 + addl 104(%esp),%eax + # x7 = s + movl %ecx,128(%esp) + # t += x11 + addl 144(%esp),%edx + # x13 = w + movl %ebx,152(%esp) + # p <<<= 13 + rol $13,%eax + # p ^= x3 + xorl 112(%esp),%eax + # t <<<= 13 + rol $13,%edx + # t ^= x9 + xorl 136(%esp),%edx + # r += s + add %ecx,%esi + # r <<<= 13 + rol $13,%esi + # r ^= x4 + xorl 116(%esp),%esi + # v += w + add %ebx,%edi + # v <<<= 13 + rol $13,%edi + # v ^= x14 + xorl 156(%esp),%edi + # x3 = p + movl %eax,112(%esp) + # x9 = t + movl %edx,136(%esp) + # p += x2 + addl 108(%esp),%eax + # x4 = r + movl %esi,116(%esp) + # t += x8 + addl 132(%esp),%edx + # x14 = v + movl %edi,156(%esp) + # p <<<= 18 + rol $18,%eax + # p ^= x0 + xorl 100(%esp),%eax + # t <<<= 18 + rol $18,%edx + # t ^= x10 + xorl 140(%esp),%edx + # s += r + add %esi,%ecx + # s <<<= 18 + rol $18,%ecx + # s ^= x5 + xorl 120(%esp),%ecx + # w += v + add %edi,%ebx + # w <<<= 18 + rol $18,%ebx + # w ^= x15 + xorl 160(%esp),%ebx + # x0 = p + movl %eax,100(%esp) + # x10 = t + movl %edx,140(%esp) + # p += x12 + addl 148(%esp),%eax + # x5 = s + movl %ecx,120(%esp) + # t += x6 + addl 124(%esp),%edx + # x15 = w + movl %ebx,160(%esp) + # r = x1 + movl 104(%esp),%esi + # r += s + add %ecx,%esi + # v = x11 + movl 144(%esp),%edi + # v += w + add %ebx,%edi + # p <<<= 7 + rol $7,%eax + # p ^= x4 + xorl 116(%esp),%eax + # t <<<= 7 + rol $7,%edx + # t ^= x14 + xorl 156(%esp),%edx + # r <<<= 7 + rol $7,%esi + # r ^= x9 + xorl 136(%esp),%esi + # v <<<= 7 + rol $7,%edi + # v ^= x3 + xorl 112(%esp),%edi + # x4 = p + movl %eax,116(%esp) + # x14 = t + movl %edx,156(%esp) + # p += x0 + addl 100(%esp),%eax + # x9 = r + movl %esi,136(%esp) + # t += x10 + addl 140(%esp),%edx + # x3 = v + movl %edi,112(%esp) + # p <<<= 9 + rol $9,%eax + # p ^= x8 + xorl 132(%esp),%eax + # t <<<= 9 + rol $9,%edx + # t ^= x2 + xorl 108(%esp),%edx + # s += r + add %esi,%ecx + # s <<<= 9 + rol $9,%ecx + # s ^= x13 + xorl 152(%esp),%ecx + # w += v + add %edi,%ebx + # w <<<= 9 + rol $9,%ebx + # w ^= x7 + xorl 128(%esp),%ebx + # x8 = p + movl %eax,132(%esp) + # x2 = t + movl %edx,108(%esp) + # p += x4 + addl 116(%esp),%eax + # x13 = s + movl %ecx,152(%esp) + # t += x14 + addl 156(%esp),%edx + # x7 = w + movl %ebx,128(%esp) + # p <<<= 13 + rol $13,%eax + # p ^= x12 + xorl 148(%esp),%eax + # t <<<= 13 + rol $13,%edx + # t ^= x6 + xorl 124(%esp),%edx + # r += s + add %ecx,%esi + # r <<<= 13 + rol $13,%esi + # r ^= x1 + xorl 104(%esp),%esi + # v += w + add %ebx,%edi + # v <<<= 13 + rol $13,%edi + # v ^= x11 + xorl 144(%esp),%edi + # x12 = p + movl %eax,148(%esp) + # x6 = t + movl %edx,124(%esp) + # p += x8 + addl 132(%esp),%eax + # x1 = r + movl %esi,104(%esp) + # t += x2 + addl 108(%esp),%edx + # x11 = v + movl %edi,144(%esp) + # p <<<= 18 + rol $18,%eax + # p ^= x0 + xorl 100(%esp),%eax + # t <<<= 18 + rol $18,%edx + # t ^= x10 + xorl 140(%esp),%edx + # s += r + add %esi,%ecx + # s <<<= 18 + rol $18,%ecx + # s ^= x5 + xorl 120(%esp),%ecx + # w += v + add %edi,%ebx + # w <<<= 18 + rol $18,%ebx + # w ^= x15 + xorl 160(%esp),%ebx + # x0 = p + movl %eax,100(%esp) + # x10 = t + movl %edx,140(%esp) + # p += x3 + addl 112(%esp),%eax + # p <<<= 7 + rol $7,%eax + # x5 = s + movl %ecx,120(%esp) + # t += x9 + addl 136(%esp),%edx + # x15 = w + movl %ebx,160(%esp) + # r = x4 + movl 116(%esp),%esi + # r += s + add %ecx,%esi + # v = x14 + movl 156(%esp),%edi + # v += w + add %ebx,%edi + # p ^= x1 + xorl 104(%esp),%eax + # t <<<= 7 + rol $7,%edx + # t ^= x11 + xorl 144(%esp),%edx + # r <<<= 7 + rol $7,%esi + # r ^= x6 + xorl 124(%esp),%esi + # v <<<= 7 + rol $7,%edi + # v ^= x12 + xorl 148(%esp),%edi + # x1 = p + movl %eax,104(%esp) + # x11 = t + movl %edx,144(%esp) + # p += x0 + addl 100(%esp),%eax + # x6 = r + movl %esi,124(%esp) + # t += x10 + addl 140(%esp),%edx + # x12 = v + movl %edi,148(%esp) + # p <<<= 9 + rol $9,%eax + # p ^= x2 + xorl 108(%esp),%eax + # t <<<= 9 + rol $9,%edx + # t ^= x8 + xorl 132(%esp),%edx + # s += r + add %esi,%ecx + # s <<<= 9 + rol $9,%ecx + # s ^= x7 + xorl 128(%esp),%ecx + # w += v + add %edi,%ebx + # w <<<= 9 + rol $9,%ebx + # w ^= x13 + xorl 152(%esp),%ebx + # x2 = p + movl %eax,108(%esp) + # x8 = t + movl %edx,132(%esp) + # p += x1 + addl 104(%esp),%eax + # x7 = s + movl %ecx,128(%esp) + # t += x11 + addl 144(%esp),%edx + # x13 = w + movl %ebx,152(%esp) + # p <<<= 13 + rol $13,%eax + # p ^= x3 + xorl 112(%esp),%eax + # t <<<= 13 + rol $13,%edx + # t ^= x9 + xorl 136(%esp),%edx + # r += s + add %ecx,%esi + # r <<<= 13 + rol $13,%esi + # r ^= x4 + xorl 116(%esp),%esi + # v += w + add %ebx,%edi + # v <<<= 13 + rol $13,%edi + # v ^= x14 + xorl 156(%esp),%edi + # x3 = p + movl %eax,112(%esp) + # x9 = t + movl %edx,136(%esp) + # p += x2 + addl 108(%esp),%eax + # x4 = r + movl %esi,116(%esp) + # t += x8 + addl 132(%esp),%edx + # x14 = v + movl %edi,156(%esp) + # p <<<= 18 + rol $18,%eax + # p ^= x0 + xorl 100(%esp),%eax + # t <<<= 18 + rol $18,%edx + # t ^= x10 + xorl 140(%esp),%edx + # s += r + add %esi,%ecx + # s <<<= 18 + rol $18,%ecx + # s ^= x5 + xorl 120(%esp),%ecx + # w += v + add %edi,%ebx + # w <<<= 18 + rol $18,%ebx + # w ^= x15 + xorl 160(%esp),%ebx + # i -= 4 + sub $4,%ebp + # goto mainloop if unsigned > + ja ._mainloop + # x0 = p + movl %eax,100(%esp) + # x5 = s + movl %ecx,120(%esp) + # x10 = t + movl %edx,140(%esp) + # x15 = w + movl %ebx,160(%esp) + # out = out_backup + movl 72(%esp),%edi + # m = m_backup + movl 68(%esp),%esi + # in0 = x0 + movl 100(%esp),%eax + # in1 = x1 + movl 104(%esp),%ecx + # in0 += j0 + addl 164(%esp),%eax + # in1 += j1 + addl 168(%esp),%ecx + # in0 ^= *(uint32 *) (m + 0) + xorl 0(%esi),%eax + # in1 ^= *(uint32 *) (m + 4) + xorl 4(%esi),%ecx + # *(uint32 *) (out + 0) = in0 + movl %eax,0(%edi) + # *(uint32 *) (out + 4) = in1 + movl %ecx,4(%edi) + # in2 = x2 + movl 108(%esp),%eax + # in3 = x3 + movl 112(%esp),%ecx + # in2 += j2 + addl 172(%esp),%eax + # in3 += j3 + addl 176(%esp),%ecx + # in2 ^= *(uint32 *) (m + 8) + xorl 8(%esi),%eax + # in3 ^= *(uint32 *) (m + 12) + xorl 12(%esi),%ecx + # *(uint32 *) (out + 8) = in2 + movl %eax,8(%edi) + # *(uint32 *) (out + 12) = in3 + movl %ecx,12(%edi) + # in4 = x4 + movl 116(%esp),%eax + # in5 = x5 + movl 120(%esp),%ecx + # in4 += j4 + addl 180(%esp),%eax + # in5 += j5 + addl 184(%esp),%ecx + # in4 ^= *(uint32 *) (m + 16) + xorl 16(%esi),%eax + # in5 ^= *(uint32 *) (m + 20) + xorl 20(%esi),%ecx + # *(uint32 *) (out + 16) = in4 + movl %eax,16(%edi) + # *(uint32 *) (out + 20) = in5 + movl %ecx,20(%edi) + # in6 = x6 + movl 124(%esp),%eax + # in7 = x7 + movl 128(%esp),%ecx + # in6 += j6 + addl 188(%esp),%eax + # in7 += j7 + addl 192(%esp),%ecx + # in6 ^= *(uint32 *) (m + 24) + xorl 24(%esi),%eax + # in7 ^= *(uint32 *) (m + 28) + xorl 28(%esi),%ecx + # *(uint32 *) (out + 24) = in6 + movl %eax,24(%edi) + # *(uint32 *) (out + 28) = in7 + movl %ecx,28(%edi) + # in8 = x8 + movl 132(%esp),%eax + # in9 = x9 + movl 136(%esp),%ecx + # in8 += j8 + addl 196(%esp),%eax + # in9 += j9 + addl 200(%esp),%ecx + # in8 ^= *(uint32 *) (m + 32) + xorl 32(%esi),%eax + # in9 ^= *(uint32 *) (m + 36) + xorl 36(%esi),%ecx + # *(uint32 *) (out + 32) = in8 + movl %eax,32(%edi) + # *(uint32 *) (out + 36) = in9 + movl %ecx,36(%edi) + # in10 = x10 + movl 140(%esp),%eax + # in11 = x11 + movl 144(%esp),%ecx + # in10 += j10 + addl 204(%esp),%eax + # in11 += j11 + addl 208(%esp),%ecx + # in10 ^= *(uint32 *) (m + 40) + xorl 40(%esi),%eax + # in11 ^= *(uint32 *) (m + 44) + xorl 44(%esi),%ecx + # *(uint32 *) (out + 40) = in10 + movl %eax,40(%edi) + # *(uint32 *) (out + 44) = in11 + movl %ecx,44(%edi) + # in12 = x12 + movl 148(%esp),%eax + # in13 = x13 + movl 152(%esp),%ecx + # in12 += j12 + addl 212(%esp),%eax + # in13 += j13 + addl 216(%esp),%ecx + # in12 ^= *(uint32 *) (m + 48) + xorl 48(%esi),%eax + # in13 ^= *(uint32 *) (m + 52) + xorl 52(%esi),%ecx + # *(uint32 *) (out + 48) = in12 + movl %eax,48(%edi) + # *(uint32 *) (out + 52) = in13 + movl %ecx,52(%edi) + # in14 = x14 + movl 156(%esp),%eax + # in15 = x15 + movl 160(%esp),%ecx + # in14 += j14 + addl 220(%esp),%eax + # in15 += j15 + addl 224(%esp),%ecx + # in14 ^= *(uint32 *) (m + 56) + xorl 56(%esi),%eax + # in15 ^= *(uint32 *) (m + 60) + xorl 60(%esi),%ecx + # *(uint32 *) (out + 56) = in14 + movl %eax,56(%edi) + # *(uint32 *) (out + 60) = in15 + movl %ecx,60(%edi) + # bytes = bytes_backup + movl 76(%esp),%ebx + # in8 = j8 + movl 196(%esp),%eax + # in9 = j9 + movl 200(%esp),%ecx + # in8 += 1 + add $1,%eax + # in9 += 0 + carry + adc $0,%ecx + # j8 = in8 + movl %eax,196(%esp) + # j9 = in9 + movl %ecx,200(%esp) + # bytes - 64 + cmp $64,%ebx + # goto bytesatleast65 if unsigned> + ja ._bytesatleast65 + # goto bytesatleast64 if unsigned>= + jae ._bytesatleast64 + # m = out + mov %edi,%esi + # out = ctarget + movl 228(%esp),%edi + # i = bytes + mov %ebx,%ecx + # while (i) { *out++ = *m++; --i } + rep movsb +._bytesatleast64: + # x = x_backup + movl 64(%esp),%eax + # in8 = j8 + movl 196(%esp),%ecx + # in9 = j9 + movl 200(%esp),%edx + # *(uint32 *) (x + 32) = in8 + movl %ecx,32(%eax) + # *(uint32 *) (x + 36) = in9 + movl %edx,36(%eax) +._done: + # eax = eax_stack + movl 80(%esp),%eax + # ebx = ebx_stack + movl 84(%esp),%ebx + # esi = esi_stack + movl 88(%esp),%esi + # edi = edi_stack + movl 92(%esp),%edi + # ebp = ebp_stack + movl 96(%esp),%ebp + # leave + add %eax,%esp + ret +._bytesatleast65: + # bytes -= 64 + sub $64,%ebx + # out += 64 + add $64,%edi + # m += 64 + add $64,%esi + # goto bytesatleast1 + jmp ._bytesatleast1 +# enter ECRYPT_keysetup +.text +.p2align 5 +.globl ECRYPT_keysetup +ECRYPT_keysetup: + mov %esp,%eax + and $31,%eax + add $256,%eax + sub %eax,%esp + # eax_stack = eax + movl %eax,64(%esp) + # ebx_stack = ebx + movl %ebx,68(%esp) + # esi_stack = esi + movl %esi,72(%esp) + # edi_stack = edi + movl %edi,76(%esp) + # ebp_stack = ebp + movl %ebp,80(%esp) + # k = arg2 + movl 8(%esp,%eax),%ecx + # kbits = arg3 + movl 12(%esp,%eax),%edx + # x = arg1 + movl 4(%esp,%eax),%eax + # in1 = *(uint32 *) (k + 0) + movl 0(%ecx),%ebx + # in2 = *(uint32 *) (k + 4) + movl 4(%ecx),%esi + # in3 = *(uint32 *) (k + 8) + movl 8(%ecx),%edi + # in4 = *(uint32 *) (k + 12) + movl 12(%ecx),%ebp + # *(uint32 *) (x + 4) = in1 + movl %ebx,4(%eax) + # *(uint32 *) (x + 8) = in2 + movl %esi,8(%eax) + # *(uint32 *) (x + 12) = in3 + movl %edi,12(%eax) + # *(uint32 *) (x + 16) = in4 + movl %ebp,16(%eax) + # kbits - 256 + cmp $256,%edx + # goto kbits128 if unsigned< + jb ._kbits128 +._kbits256: + # in11 = *(uint32 *) (k + 16) + movl 16(%ecx),%edx + # in12 = *(uint32 *) (k + 20) + movl 20(%ecx),%ebx + # in13 = *(uint32 *) (k + 24) + movl 24(%ecx),%esi + # in14 = *(uint32 *) (k + 28) + movl 28(%ecx),%ecx + # *(uint32 *) (x + 44) = in11 + movl %edx,44(%eax) + # *(uint32 *) (x + 48) = in12 + movl %ebx,48(%eax) + # *(uint32 *) (x + 52) = in13 + movl %esi,52(%eax) + # *(uint32 *) (x + 56) = in14 + movl %ecx,56(%eax) + # in0 = 1634760805 + mov $1634760805,%ecx + # in5 = 857760878 + mov $857760878,%edx + # in10 = 2036477234 + mov $2036477234,%ebx + # in15 = 1797285236 + mov $1797285236,%esi + # *(uint32 *) (x + 0) = in0 + movl %ecx,0(%eax) + # *(uint32 *) (x + 20) = in5 + movl %edx,20(%eax) + # *(uint32 *) (x + 40) = in10 + movl %ebx,40(%eax) + # *(uint32 *) (x + 60) = in15 + movl %esi,60(%eax) + # goto keysetupdone + jmp ._keysetupdone +._kbits128: + # in11 = *(uint32 *) (k + 0) + movl 0(%ecx),%edx + # in12 = *(uint32 *) (k + 4) + movl 4(%ecx),%ebx + # in13 = *(uint32 *) (k + 8) + movl 8(%ecx),%esi + # in14 = *(uint32 *) (k + 12) + movl 12(%ecx),%ecx + # *(uint32 *) (x + 44) = in11 + movl %edx,44(%eax) + # *(uint32 *) (x + 48) = in12 + movl %ebx,48(%eax) + # *(uint32 *) (x + 52) = in13 + movl %esi,52(%eax) + # *(uint32 *) (x + 56) = in14 + movl %ecx,56(%eax) + # in0 = 1634760805 + mov $1634760805,%ecx + # in5 = 824206446 + mov $824206446,%edx + # in10 = 2036477238 + mov $2036477238,%ebx + # in15 = 1797285236 + mov $1797285236,%esi + # *(uint32 *) (x + 0) = in0 + movl %ecx,0(%eax) + # *(uint32 *) (x + 20) = in5 + movl %edx,20(%eax) + # *(uint32 *) (x + 40) = in10 + movl %ebx,40(%eax) + # *(uint32 *) (x + 60) = in15 + movl %esi,60(%eax) +._keysetupdone: + # eax = eax_stack + movl 64(%esp),%eax + # ebx = ebx_stack + movl 68(%esp),%ebx + # esi = esi_stack + movl 72(%esp),%esi + # edi = edi_stack + movl 76(%esp),%edi + # ebp = ebp_stack + movl 80(%esp),%ebp + # leave + add %eax,%esp + ret +# enter ECRYPT_ivsetup +.text +.p2align 5 +.globl ECRYPT_ivsetup +ECRYPT_ivsetup: + mov %esp,%eax + and $31,%eax + add $256,%eax + sub %eax,%esp + # eax_stack = eax + movl %eax,64(%esp) + # ebx_stack = ebx + movl %ebx,68(%esp) + # esi_stack = esi + movl %esi,72(%esp) + # edi_stack = edi + movl %edi,76(%esp) + # ebp_stack = ebp + movl %ebp,80(%esp) + # iv = arg2 + movl 8(%esp,%eax),%ecx + # x = arg1 + movl 4(%esp,%eax),%eax + # in6 = *(uint32 *) (iv + 0) + movl 0(%ecx),%edx + # in7 = *(uint32 *) (iv + 4) + movl 4(%ecx),%ecx + # in8 = 0 + mov $0,%ebx + # in9 = 0 + mov $0,%esi + # *(uint32 *) (x + 24) = in6 + movl %edx,24(%eax) + # *(uint32 *) (x + 28) = in7 + movl %ecx,28(%eax) + # *(uint32 *) (x + 32) = in8 + movl %ebx,32(%eax) + # *(uint32 *) (x + 36) = in9 + movl %esi,36(%eax) + # eax = eax_stack + movl 64(%esp),%eax + # ebx = ebx_stack + movl 68(%esp),%ebx + # esi = esi_stack + movl 72(%esp),%esi + # edi = edi_stack + movl 76(%esp),%edi + # ebp = ebp_stack + movl 80(%esp),%ebp + # leave + add %eax,%esp + ret diff --git a/arch/x86/crypto/salsa20-x86_64-asm_64.S b/arch/x86/crypto/salsa20-x86_64-asm_64.S new file mode 100644 index 000000000000..6214a9b09706 --- /dev/null +++ b/arch/x86/crypto/salsa20-x86_64-asm_64.S @@ -0,0 +1,920 @@ +# enter ECRYPT_encrypt_bytes +.text +.p2align 5 +.globl ECRYPT_encrypt_bytes +ECRYPT_encrypt_bytes: + mov %rsp,%r11 + and $31,%r11 + add $256,%r11 + sub %r11,%rsp + # x = arg1 + mov %rdi,%r8 + # m = arg2 + mov %rsi,%rsi + # out = arg3 + mov %rdx,%rdi + # bytes = arg4 + mov %rcx,%rdx + # unsigned>? bytes - 0 + cmp $0,%rdx + # comment:fp stack unchanged by jump + # goto done if !unsigned> + jbe ._done + # comment:fp stack unchanged by fallthrough +# start: +._start: + # r11_stack = r11 + movq %r11,0(%rsp) + # r12_stack = r12 + movq %r12,8(%rsp) + # r13_stack = r13 + movq %r13,16(%rsp) + # r14_stack = r14 + movq %r14,24(%rsp) + # r15_stack = r15 + movq %r15,32(%rsp) + # rbx_stack = rbx + movq %rbx,40(%rsp) + # rbp_stack = rbp + movq %rbp,48(%rsp) + # in0 = *(uint64 *) (x + 0) + movq 0(%r8),%rcx + # in2 = *(uint64 *) (x + 8) + movq 8(%r8),%r9 + # in4 = *(uint64 *) (x + 16) + movq 16(%r8),%rax + # in6 = *(uint64 *) (x + 24) + movq 24(%r8),%r10 + # in8 = *(uint64 *) (x + 32) + movq 32(%r8),%r11 + # in10 = *(uint64 *) (x + 40) + movq 40(%r8),%r12 + # in12 = *(uint64 *) (x + 48) + movq 48(%r8),%r13 + # in14 = *(uint64 *) (x + 56) + movq 56(%r8),%r14 + # j0 = in0 + movq %rcx,56(%rsp) + # j2 = in2 + movq %r9,64(%rsp) + # j4 = in4 + movq %rax,72(%rsp) + # j6 = in6 + movq %r10,80(%rsp) + # j8 = in8 + movq %r11,88(%rsp) + # j10 = in10 + movq %r12,96(%rsp) + # j12 = in12 + movq %r13,104(%rsp) + # j14 = in14 + movq %r14,112(%rsp) + # x_backup = x + movq %r8,120(%rsp) +# bytesatleast1: +._bytesatleast1: + # unsigned<? bytes - 64 + cmp $64,%rdx + # comment:fp stack unchanged by jump + # goto nocopy if !unsigned< + jae ._nocopy + # ctarget = out + movq %rdi,128(%rsp) + # out = &tmp + leaq 192(%rsp),%rdi + # i = bytes + mov %rdx,%rcx + # while (i) { *out++ = *m++; --i } + rep movsb + # out = &tmp + leaq 192(%rsp),%rdi + # m = &tmp + leaq 192(%rsp),%rsi + # comment:fp stack unchanged by fallthrough +# nocopy: +._nocopy: + # out_backup = out + movq %rdi,136(%rsp) + # m_backup = m + movq %rsi,144(%rsp) + # bytes_backup = bytes + movq %rdx,152(%rsp) + # x1 = j0 + movq 56(%rsp),%rdi + # x0 = x1 + mov %rdi,%rdx + # (uint64) x1 >>= 32 + shr $32,%rdi + # x3 = j2 + movq 64(%rsp),%rsi + # x2 = x3 + mov %rsi,%rcx + # (uint64) x3 >>= 32 + shr $32,%rsi + # x5 = j4 + movq 72(%rsp),%r8 + # x4 = x5 + mov %r8,%r9 + # (uint64) x5 >>= 32 + shr $32,%r8 + # x5_stack = x5 + movq %r8,160(%rsp) + # x7 = j6 + movq 80(%rsp),%r8 + # x6 = x7 + mov %r8,%rax + # (uint64) x7 >>= 32 + shr $32,%r8 + # x9 = j8 + movq 88(%rsp),%r10 + # x8 = x9 + mov %r10,%r11 + # (uint64) x9 >>= 32 + shr $32,%r10 + # x11 = j10 + movq 96(%rsp),%r12 + # x10 = x11 + mov %r12,%r13 + # x10_stack = x10 + movq %r13,168(%rsp) + # (uint64) x11 >>= 32 + shr $32,%r12 + # x13 = j12 + movq 104(%rsp),%r13 + # x12 = x13 + mov %r13,%r14 + # (uint64) x13 >>= 32 + shr $32,%r13 + # x15 = j14 + movq 112(%rsp),%r15 + # x14 = x15 + mov %r15,%rbx + # (uint64) x15 >>= 32 + shr $32,%r15 + # x15_stack = x15 + movq %r15,176(%rsp) + # i = 20 + mov $20,%r15 +# mainloop: +._mainloop: + # i_backup = i + movq %r15,184(%rsp) + # x5 = x5_stack + movq 160(%rsp),%r15 + # a = x12 + x0 + lea (%r14,%rdx),%rbp + # (uint32) a <<<= 7 + rol $7,%ebp + # x4 ^= a + xor %rbp,%r9 + # b = x1 + x5 + lea (%rdi,%r15),%rbp + # (uint32) b <<<= 7 + rol $7,%ebp + # x9 ^= b + xor %rbp,%r10 + # a = x0 + x4 + lea (%rdx,%r9),%rbp + # (uint32) a <<<= 9 + rol $9,%ebp + # x8 ^= a + xor %rbp,%r11 + # b = x5 + x9 + lea (%r15,%r10),%rbp + # (uint32) b <<<= 9 + rol $9,%ebp + # x13 ^= b + xor %rbp,%r13 + # a = x4 + x8 + lea (%r9,%r11),%rbp + # (uint32) a <<<= 13 + rol $13,%ebp + # x12 ^= a + xor %rbp,%r14 + # b = x9 + x13 + lea (%r10,%r13),%rbp + # (uint32) b <<<= 13 + rol $13,%ebp + # x1 ^= b + xor %rbp,%rdi + # a = x8 + x12 + lea (%r11,%r14),%rbp + # (uint32) a <<<= 18 + rol $18,%ebp + # x0 ^= a + xor %rbp,%rdx + # b = x13 + x1 + lea (%r13,%rdi),%rbp + # (uint32) b <<<= 18 + rol $18,%ebp + # x5 ^= b + xor %rbp,%r15 + # x10 = x10_stack + movq 168(%rsp),%rbp + # x5_stack = x5 + movq %r15,160(%rsp) + # c = x6 + x10 + lea (%rax,%rbp),%r15 + # (uint32) c <<<= 7 + rol $7,%r15d + # x14 ^= c + xor %r15,%rbx + # c = x10 + x14 + lea (%rbp,%rbx),%r15 + # (uint32) c <<<= 9 + rol $9,%r15d + # x2 ^= c + xor %r15,%rcx + # c = x14 + x2 + lea (%rbx,%rcx),%r15 + # (uint32) c <<<= 13 + rol $13,%r15d + # x6 ^= c + xor %r15,%rax + # c = x2 + x6 + lea (%rcx,%rax),%r15 + # (uint32) c <<<= 18 + rol $18,%r15d + # x10 ^= c + xor %r15,%rbp + # x15 = x15_stack + movq 176(%rsp),%r15 + # x10_stack = x10 + movq %rbp,168(%rsp) + # d = x11 + x15 + lea (%r12,%r15),%rbp + # (uint32) d <<<= 7 + rol $7,%ebp + # x3 ^= d + xor %rbp,%rsi + # d = x15 + x3 + lea (%r15,%rsi),%rbp + # (uint32) d <<<= 9 + rol $9,%ebp + # x7 ^= d + xor %rbp,%r8 + # d = x3 + x7 + lea (%rsi,%r8),%rbp + # (uint32) d <<<= 13 + rol $13,%ebp + # x11 ^= d + xor %rbp,%r12 + # d = x7 + x11 + lea (%r8,%r12),%rbp + # (uint32) d <<<= 18 + rol $18,%ebp + # x15 ^= d + xor %rbp,%r15 + # x15_stack = x15 + movq %r15,176(%rsp) + # x5 = x5_stack + movq 160(%rsp),%r15 + # a = x3 + x0 + lea (%rsi,%rdx),%rbp + # (uint32) a <<<= 7 + rol $7,%ebp + # x1 ^= a + xor %rbp,%rdi + # b = x4 + x5 + lea (%r9,%r15),%rbp + # (uint32) b <<<= 7 + rol $7,%ebp + # x6 ^= b + xor %rbp,%rax + # a = x0 + x1 + lea (%rdx,%rdi),%rbp + # (uint32) a <<<= 9 + rol $9,%ebp + # x2 ^= a + xor %rbp,%rcx + # b = x5 + x6 + lea (%r15,%rax),%rbp + # (uint32) b <<<= 9 + rol $9,%ebp + # x7 ^= b + xor %rbp,%r8 + # a = x1 + x2 + lea (%rdi,%rcx),%rbp + # (uint32) a <<<= 13 + rol $13,%ebp + # x3 ^= a + xor %rbp,%rsi + # b = x6 + x7 + lea (%rax,%r8),%rbp + # (uint32) b <<<= 13 + rol $13,%ebp + # x4 ^= b + xor %rbp,%r9 + # a = x2 + x3 + lea (%rcx,%rsi),%rbp + # (uint32) a <<<= 18 + rol $18,%ebp + # x0 ^= a + xor %rbp,%rdx + # b = x7 + x4 + lea (%r8,%r9),%rbp + # (uint32) b <<<= 18 + rol $18,%ebp + # x5 ^= b + xor %rbp,%r15 + # x10 = x10_stack + movq 168(%rsp),%rbp + # x5_stack = x5 + movq %r15,160(%rsp) + # c = x9 + x10 + lea (%r10,%rbp),%r15 + # (uint32) c <<<= 7 + rol $7,%r15d + # x11 ^= c + xor %r15,%r12 + # c = x10 + x11 + lea (%rbp,%r12),%r15 + # (uint32) c <<<= 9 + rol $9,%r15d + # x8 ^= c + xor %r15,%r11 + # c = x11 + x8 + lea (%r12,%r11),%r15 + # (uint32) c <<<= 13 + rol $13,%r15d + # x9 ^= c + xor %r15,%r10 + # c = x8 + x9 + lea (%r11,%r10),%r15 + # (uint32) c <<<= 18 + rol $18,%r15d + # x10 ^= c + xor %r15,%rbp + # x15 = x15_stack + movq 176(%rsp),%r15 + # x10_stack = x10 + movq %rbp,168(%rsp) + # d = x14 + x15 + lea (%rbx,%r15),%rbp + # (uint32) d <<<= 7 + rol $7,%ebp + # x12 ^= d + xor %rbp,%r14 + # d = x15 + x12 + lea (%r15,%r14),%rbp + # (uint32) d <<<= 9 + rol $9,%ebp + # x13 ^= d + xor %rbp,%r13 + # d = x12 + x13 + lea (%r14,%r13),%rbp + # (uint32) d <<<= 13 + rol $13,%ebp + # x14 ^= d + xor %rbp,%rbx + # d = x13 + x14 + lea (%r13,%rbx),%rbp + # (uint32) d <<<= 18 + rol $18,%ebp + # x15 ^= d + xor %rbp,%r15 + # x15_stack = x15 + movq %r15,176(%rsp) + # x5 = x5_stack + movq 160(%rsp),%r15 + # a = x12 + x0 + lea (%r14,%rdx),%rbp + # (uint32) a <<<= 7 + rol $7,%ebp + # x4 ^= a + xor %rbp,%r9 + # b = x1 + x5 + lea (%rdi,%r15),%rbp + # (uint32) b <<<= 7 + rol $7,%ebp + # x9 ^= b + xor %rbp,%r10 + # a = x0 + x4 + lea (%rdx,%r9),%rbp + # (uint32) a <<<= 9 + rol $9,%ebp + # x8 ^= a + xor %rbp,%r11 + # b = x5 + x9 + lea (%r15,%r10),%rbp + # (uint32) b <<<= 9 + rol $9,%ebp + # x13 ^= b + xor %rbp,%r13 + # a = x4 + x8 + lea (%r9,%r11),%rbp + # (uint32) a <<<= 13 + rol $13,%ebp + # x12 ^= a + xor %rbp,%r14 + # b = x9 + x13 + lea (%r10,%r13),%rbp + # (uint32) b <<<= 13 + rol $13,%ebp + # x1 ^= b + xor %rbp,%rdi + # a = x8 + x12 + lea (%r11,%r14),%rbp + # (uint32) a <<<= 18 + rol $18,%ebp + # x0 ^= a + xor %rbp,%rdx + # b = x13 + x1 + lea (%r13,%rdi),%rbp + # (uint32) b <<<= 18 + rol $18,%ebp + # x5 ^= b + xor %rbp,%r15 + # x10 = x10_stack + movq 168(%rsp),%rbp + # x5_stack = x5 + movq %r15,160(%rsp) + # c = x6 + x10 + lea (%rax,%rbp),%r15 + # (uint32) c <<<= 7 + rol $7,%r15d + # x14 ^= c + xor %r15,%rbx + # c = x10 + x14 + lea (%rbp,%rbx),%r15 + # (uint32) c <<<= 9 + rol $9,%r15d + # x2 ^= c + xor %r15,%rcx + # c = x14 + x2 + lea (%rbx,%rcx),%r15 + # (uint32) c <<<= 13 + rol $13,%r15d + # x6 ^= c + xor %r15,%rax + # c = x2 + x6 + lea (%rcx,%rax),%r15 + # (uint32) c <<<= 18 + rol $18,%r15d + # x10 ^= c + xor %r15,%rbp + # x15 = x15_stack + movq 176(%rsp),%r15 + # x10_stack = x10 + movq %rbp,168(%rsp) + # d = x11 + x15 + lea (%r12,%r15),%rbp + # (uint32) d <<<= 7 + rol $7,%ebp + # x3 ^= d + xor %rbp,%rsi + # d = x15 + x3 + lea (%r15,%rsi),%rbp + # (uint32) d <<<= 9 + rol $9,%ebp + # x7 ^= d + xor %rbp,%r8 + # d = x3 + x7 + lea (%rsi,%r8),%rbp + # (uint32) d <<<= 13 + rol $13,%ebp + # x11 ^= d + xor %rbp,%r12 + # d = x7 + x11 + lea (%r8,%r12),%rbp + # (uint32) d <<<= 18 + rol $18,%ebp + # x15 ^= d + xor %rbp,%r15 + # x15_stack = x15 + movq %r15,176(%rsp) + # x5 = x5_stack + movq 160(%rsp),%r15 + # a = x3 + x0 + lea (%rsi,%rdx),%rbp + # (uint32) a <<<= 7 + rol $7,%ebp + # x1 ^= a + xor %rbp,%rdi + # b = x4 + x5 + lea (%r9,%r15),%rbp + # (uint32) b <<<= 7 + rol $7,%ebp + # x6 ^= b + xor %rbp,%rax + # a = x0 + x1 + lea (%rdx,%rdi),%rbp + # (uint32) a <<<= 9 + rol $9,%ebp + # x2 ^= a + xor %rbp,%rcx + # b = x5 + x6 + lea (%r15,%rax),%rbp + # (uint32) b <<<= 9 + rol $9,%ebp + # x7 ^= b + xor %rbp,%r8 + # a = x1 + x2 + lea (%rdi,%rcx),%rbp + # (uint32) a <<<= 13 + rol $13,%ebp + # x3 ^= a + xor %rbp,%rsi + # b = x6 + x7 + lea (%rax,%r8),%rbp + # (uint32) b <<<= 13 + rol $13,%ebp + # x4 ^= b + xor %rbp,%r9 + # a = x2 + x3 + lea (%rcx,%rsi),%rbp + # (uint32) a <<<= 18 + rol $18,%ebp + # x0 ^= a + xor %rbp,%rdx + # b = x7 + x4 + lea (%r8,%r9),%rbp + # (uint32) b <<<= 18 + rol $18,%ebp + # x5 ^= b + xor %rbp,%r15 + # x10 = x10_stack + movq 168(%rsp),%rbp + # x5_stack = x5 + movq %r15,160(%rsp) + # c = x9 + x10 + lea (%r10,%rbp),%r15 + # (uint32) c <<<= 7 + rol $7,%r15d + # x11 ^= c + xor %r15,%r12 + # c = x10 + x11 + lea (%rbp,%r12),%r15 + # (uint32) c <<<= 9 + rol $9,%r15d + # x8 ^= c + xor %r15,%r11 + # c = x11 + x8 + lea (%r12,%r11),%r15 + # (uint32) c <<<= 13 + rol $13,%r15d + # x9 ^= c + xor %r15,%r10 + # c = x8 + x9 + lea (%r11,%r10),%r15 + # (uint32) c <<<= 18 + rol $18,%r15d + # x10 ^= c + xor %r15,%rbp + # x15 = x15_stack + movq 176(%rsp),%r15 + # x10_stack = x10 + movq %rbp,168(%rsp) + # d = x14 + x15 + lea (%rbx,%r15),%rbp + # (uint32) d <<<= 7 + rol $7,%ebp + # x12 ^= d + xor %rbp,%r14 + # d = x15 + x12 + lea (%r15,%r14),%rbp + # (uint32) d <<<= 9 + rol $9,%ebp + # x13 ^= d + xor %rbp,%r13 + # d = x12 + x13 + lea (%r14,%r13),%rbp + # (uint32) d <<<= 13 + rol $13,%ebp + # x14 ^= d + xor %rbp,%rbx + # d = x13 + x14 + lea (%r13,%rbx),%rbp + # (uint32) d <<<= 18 + rol $18,%ebp + # x15 ^= d + xor %rbp,%r15 + # x15_stack = x15 + movq %r15,176(%rsp) + # i = i_backup + movq 184(%rsp),%r15 + # unsigned>? i -= 4 + sub $4,%r15 + # comment:fp stack unchanged by jump + # goto mainloop if unsigned> + ja ._mainloop + # (uint32) x2 += j2 + addl 64(%rsp),%ecx + # x3 <<= 32 + shl $32,%rsi + # x3 += j2 + addq 64(%rsp),%rsi + # (uint64) x3 >>= 32 + shr $32,%rsi + # x3 <<= 32 + shl $32,%rsi + # x2 += x3 + add %rsi,%rcx + # (uint32) x6 += j6 + addl 80(%rsp),%eax + # x7 <<= 32 + shl $32,%r8 + # x7 += j6 + addq 80(%rsp),%r8 + # (uint64) x7 >>= 32 + shr $32,%r8 + # x7 <<= 32 + shl $32,%r8 + # x6 += x7 + add %r8,%rax + # (uint32) x8 += j8 + addl 88(%rsp),%r11d + # x9 <<= 32 + shl $32,%r10 + # x9 += j8 + addq 88(%rsp),%r10 + # (uint64) x9 >>= 32 + shr $32,%r10 + # x9 <<= 32 + shl $32,%r10 + # x8 += x9 + add %r10,%r11 + # (uint32) x12 += j12 + addl 104(%rsp),%r14d + # x13 <<= 32 + shl $32,%r13 + # x13 += j12 + addq 104(%rsp),%r13 + # (uint64) x13 >>= 32 + shr $32,%r13 + # x13 <<= 32 + shl $32,%r13 + # x12 += x13 + add %r13,%r14 + # (uint32) x0 += j0 + addl 56(%rsp),%edx + # x1 <<= 32 + shl $32,%rdi + # x1 += j0 + addq 56(%rsp),%rdi + # (uint64) x1 >>= 32 + shr $32,%rdi + # x1 <<= 32 + shl $32,%rdi + # x0 += x1 + add %rdi,%rdx + # x5 = x5_stack + movq 160(%rsp),%rdi + # (uint32) x4 += j4 + addl 72(%rsp),%r9d + # x5 <<= 32 + shl $32,%rdi + # x5 += j4 + addq 72(%rsp),%rdi + # (uint64) x5 >>= 32 + shr $32,%rdi + # x5 <<= 32 + shl $32,%rdi + # x4 += x5 + add %rdi,%r9 + # x10 = x10_stack + movq 168(%rsp),%r8 + # (uint32) x10 += j10 + addl 96(%rsp),%r8d + # x11 <<= 32 + shl $32,%r12 + # x11 += j10 + addq 96(%rsp),%r12 + # (uint64) x11 >>= 32 + shr $32,%r12 + # x11 <<= 32 + shl $32,%r12 + # x10 += x11 + add %r12,%r8 + # x15 = x15_stack + movq 176(%rsp),%rdi + # (uint32) x14 += j14 + addl 112(%rsp),%ebx + # x15 <<= 32 + shl $32,%rdi + # x15 += j14 + addq 112(%rsp),%rdi + # (uint64) x15 >>= 32 + shr $32,%rdi + # x15 <<= 32 + shl $32,%rdi + # x14 += x15 + add %rdi,%rbx + # out = out_backup + movq 136(%rsp),%rdi + # m = m_backup + movq 144(%rsp),%rsi + # x0 ^= *(uint64 *) (m + 0) + xorq 0(%rsi),%rdx + # *(uint64 *) (out + 0) = x0 + movq %rdx,0(%rdi) + # x2 ^= *(uint64 *) (m + 8) + xorq 8(%rsi),%rcx + # *(uint64 *) (out + 8) = x2 + movq %rcx,8(%rdi) + # x4 ^= *(uint64 *) (m + 16) + xorq 16(%rsi),%r9 + # *(uint64 *) (out + 16) = x4 + movq %r9,16(%rdi) + # x6 ^= *(uint64 *) (m + 24) + xorq 24(%rsi),%rax + # *(uint64 *) (out + 24) = x6 + movq %rax,24(%rdi) + # x8 ^= *(uint64 *) (m + 32) + xorq 32(%rsi),%r11 + # *(uint64 *) (out + 32) = x8 + movq %r11,32(%rdi) + # x10 ^= *(uint64 *) (m + 40) + xorq 40(%rsi),%r8 + # *(uint64 *) (out + 40) = x10 + movq %r8,40(%rdi) + # x12 ^= *(uint64 *) (m + 48) + xorq 48(%rsi),%r14 + # *(uint64 *) (out + 48) = x12 + movq %r14,48(%rdi) + # x14 ^= *(uint64 *) (m + 56) + xorq 56(%rsi),%rbx + # *(uint64 *) (out + 56) = x14 + movq %rbx,56(%rdi) + # bytes = bytes_backup + movq 152(%rsp),%rdx + # in8 = j8 + movq 88(%rsp),%rcx + # in8 += 1 + add $1,%rcx + # j8 = in8 + movq %rcx,88(%rsp) + # unsigned>? unsigned<? bytes - 64 + cmp $64,%rdx + # comment:fp stack unchanged by jump + # goto bytesatleast65 if unsigned> + ja ._bytesatleast65 + # comment:fp stack unchanged by jump + # goto bytesatleast64 if !unsigned< + jae ._bytesatleast64 + # m = out + mov %rdi,%rsi + # out = ctarget + movq 128(%rsp),%rdi + # i = bytes + mov %rdx,%rcx + # while (i) { *out++ = *m++; --i } + rep movsb + # comment:fp stack unchanged by fallthrough +# bytesatleast64: +._bytesatleast64: + # x = x_backup + movq 120(%rsp),%rdi + # in8 = j8 + movq 88(%rsp),%rsi + # *(uint64 *) (x + 32) = in8 + movq %rsi,32(%rdi) + # r11 = r11_stack + movq 0(%rsp),%r11 + # r12 = r12_stack + movq 8(%rsp),%r12 + # r13 = r13_stack + movq 16(%rsp),%r13 + # r14 = r14_stack + movq 24(%rsp),%r14 + # r15 = r15_stack + movq 32(%rsp),%r15 + # rbx = rbx_stack + movq 40(%rsp),%rbx + # rbp = rbp_stack + movq 48(%rsp),%rbp + # comment:fp stack unchanged by fallthrough +# done: +._done: + # leave + add %r11,%rsp + mov %rdi,%rax + mov %rsi,%rdx + ret +# bytesatleast65: +._bytesatleast65: + # bytes -= 64 + sub $64,%rdx + # out += 64 + add $64,%rdi + # m += 64 + add $64,%rsi + # comment:fp stack unchanged by jump + # goto bytesatleast1 + jmp ._bytesatleast1 +# enter ECRYPT_keysetup +.text +.p2align 5 +.globl ECRYPT_keysetup +ECRYPT_keysetup: + mov %rsp,%r11 + and $31,%r11 + add $256,%r11 + sub %r11,%rsp + # k = arg2 + mov %rsi,%rsi + # kbits = arg3 + mov %rdx,%rdx + # x = arg1 + mov %rdi,%rdi + # in0 = *(uint64 *) (k + 0) + movq 0(%rsi),%r8 + # in2 = *(uint64 *) (k + 8) + movq 8(%rsi),%r9 + # *(uint64 *) (x + 4) = in0 + movq %r8,4(%rdi) + # *(uint64 *) (x + 12) = in2 + movq %r9,12(%rdi) + # unsigned<? kbits - 256 + cmp $256,%rdx + # comment:fp stack unchanged by jump + # goto kbits128 if unsigned< + jb ._kbits128 +# kbits256: +._kbits256: + # in10 = *(uint64 *) (k + 16) + movq 16(%rsi),%rdx + # in12 = *(uint64 *) (k + 24) + movq 24(%rsi),%rsi + # *(uint64 *) (x + 44) = in10 + movq %rdx,44(%rdi) + # *(uint64 *) (x + 52) = in12 + movq %rsi,52(%rdi) + # in0 = 1634760805 + mov $1634760805,%rsi + # in4 = 857760878 + mov $857760878,%rdx + # in10 = 2036477234 + mov $2036477234,%rcx + # in14 = 1797285236 + mov $1797285236,%r8 + # *(uint32 *) (x + 0) = in0 + movl %esi,0(%rdi) + # *(uint32 *) (x + 20) = in4 + movl %edx,20(%rdi) + # *(uint32 *) (x + 40) = in10 + movl %ecx,40(%rdi) + # *(uint32 *) (x + 60) = in14 + movl %r8d,60(%rdi) + # comment:fp stack unchanged by jump + # goto keysetupdone + jmp ._keysetupdone +# kbits128: +._kbits128: + # in10 = *(uint64 *) (k + 0) + movq 0(%rsi),%rdx + # in12 = *(uint64 *) (k + 8) + movq 8(%rsi),%rsi + # *(uint64 *) (x + 44) = in10 + movq %rdx,44(%rdi) + # *(uint64 *) (x + 52) = in12 + movq %rsi,52(%rdi) + # in0 = 1634760805 + mov $1634760805,%rsi + # in4 = 824206446 + mov $824206446,%rdx + # in10 = 2036477238 + mov $2036477238,%rcx + # in14 = 1797285236 + mov $1797285236,%r8 + # *(uint32 *) (x + 0) = in0 + movl %esi,0(%rdi) + # *(uint32 *) (x + 20) = in4 + movl %edx,20(%rdi) + # *(uint32 *) (x + 40) = in10 + movl %ecx,40(%rdi) + # *(uint32 *) (x + 60) = in14 + movl %r8d,60(%rdi) +# keysetupdone: +._keysetupdone: + # leave + add %r11,%rsp + mov %rdi,%rax + mov %rsi,%rdx + ret +# enter ECRYPT_ivsetup +.text +.p2align 5 +.globl ECRYPT_ivsetup +ECRYPT_ivsetup: + mov %rsp,%r11 + and $31,%r11 + add $256,%r11 + sub %r11,%rsp + # iv = arg2 + mov %rsi,%rsi + # x = arg1 + mov %rdi,%rdi + # in6 = *(uint64 *) (iv + 0) + movq 0(%rsi),%rsi + # in8 = 0 + mov $0,%r8 + # *(uint64 *) (x + 24) = in6 + movq %rsi,24(%rdi) + # *(uint64 *) (x + 32) = in8 + movq %r8,32(%rdi) + # leave + add %r11,%rsp + mov %rdi,%rax + mov %rsi,%rdx + ret diff --git a/arch/x86/crypto/salsa20_glue.c b/arch/x86/crypto/salsa20_glue.c new file mode 100644 index 000000000000..bccb76d80987 --- /dev/null +++ b/arch/x86/crypto/salsa20_glue.c @@ -0,0 +1,129 @@ +/* + * Glue code for optimized assembly version of Salsa20. + * + * Copyright (c) 2007 Tan Swee Heng <thesweeheng@gmail.com> + * + * The assembly codes are public domain assembly codes written by Daniel. J. + * Bernstein <djb@cr.yp.to>. The codes are modified to include indentation + * and to remove extraneous comments and functions that are not needed. + * - i586 version, renamed as salsa20-i586-asm_32.S + * available from <http://cr.yp.to/snuffle/salsa20/x86-pm/salsa20.s> + * - x86-64 version, renamed as salsa20-x86_64-asm_64.S + * available from <http://cr.yp.to/snuffle/salsa20/amd64-3/salsa20.s> + * + * 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. + * + */ + +#include <crypto/algapi.h> +#include <linux/module.h> +#include <linux/crypto.h> + +#define SALSA20_IV_SIZE 8U +#define SALSA20_MIN_KEY_SIZE 16U +#define SALSA20_MAX_KEY_SIZE 32U + +// use the ECRYPT_* function names +#define salsa20_keysetup ECRYPT_keysetup +#define salsa20_ivsetup ECRYPT_ivsetup +#define salsa20_encrypt_bytes ECRYPT_encrypt_bytes + +struct salsa20_ctx +{ + u32 input[16]; +}; + +asmlinkage void salsa20_keysetup(struct salsa20_ctx *ctx, const u8 *k, + u32 keysize, u32 ivsize); +asmlinkage void salsa20_ivsetup(struct salsa20_ctx *ctx, const u8 *iv); +asmlinkage void salsa20_encrypt_bytes(struct salsa20_ctx *ctx, + const u8 *src, u8 *dst, u32 bytes); + +static int setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keysize) +{ + struct salsa20_ctx *ctx = crypto_tfm_ctx(tfm); + salsa20_keysetup(ctx, key, keysize*8, SALSA20_IV_SIZE*8); + return 0; +} + +static int encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct blkcipher_walk walk; + struct crypto_blkcipher *tfm = desc->tfm; + struct salsa20_ctx *ctx = crypto_blkcipher_ctx(tfm); + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt_block(desc, &walk, 64); + + salsa20_ivsetup(ctx, walk.iv); + + if (likely(walk.nbytes == nbytes)) + { + salsa20_encrypt_bytes(ctx, walk.src.virt.addr, + walk.dst.virt.addr, nbytes); + return blkcipher_walk_done(desc, &walk, 0); + } + + while (walk.nbytes >= 64) { + salsa20_encrypt_bytes(ctx, walk.src.virt.addr, + walk.dst.virt.addr, + walk.nbytes - (walk.nbytes % 64)); + err = blkcipher_walk_done(desc, &walk, walk.nbytes % 64); + } + + if (walk.nbytes) { + salsa20_encrypt_bytes(ctx, walk.src.virt.addr, + walk.dst.virt.addr, walk.nbytes); + err = blkcipher_walk_done(desc, &walk, 0); + } + + return err; +} + +static struct crypto_alg alg = { + .cra_name = "salsa20", + .cra_driver_name = "salsa20-asm", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_type = &crypto_blkcipher_type, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct salsa20_ctx), + .cra_alignmask = 3, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(alg.cra_list), + .cra_u = { + .blkcipher = { + .setkey = setkey, + .encrypt = encrypt, + .decrypt = encrypt, + .min_keysize = SALSA20_MIN_KEY_SIZE, + .max_keysize = SALSA20_MAX_KEY_SIZE, + .ivsize = SALSA20_IV_SIZE, + } + } +}; + +static int __init init(void) +{ + return crypto_register_alg(&alg); +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&alg); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION ("Salsa20 stream cipher algorithm (optimized assembly version)"); +MODULE_ALIAS("salsa20"); +MODULE_ALIAS("salsa20-asm"); diff --git a/arch/x86/crypto/twofish_64.c b/arch/x86/crypto/twofish_64.c deleted file mode 100644 index 182d91d5cfb9..000000000000 --- a/arch/x86/crypto/twofish_64.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Glue Code for optimized x86_64 assembler version of TWOFISH - * - * Originally Twofish for GPG - * By Matthew Skala <mskala@ansuz.sooke.bc.ca>, July 26, 1998 - * 256-bit key length added March 20, 1999 - * Some modifications to reduce the text size by Werner Koch, April, 1998 - * Ported to the kerneli patch by Marc Mutz <Marc@Mutz.com> - * Ported to CryptoAPI by Colin Slater <hoho@tacomeat.net> - * - * The original author has disclaimed all copyright interest in this - * code and thus put it in the public domain. The subsequent authors - * have put this under the GNU General Public License. - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - * - * This code is a "clean room" implementation, written from the paper - * _Twofish: A 128-Bit Block Cipher_ by Bruce Schneier, John Kelsey, - * Doug Whiting, David Wagner, Chris Hall, and Niels Ferguson, available - * through http://www.counterpane.com/twofish.html - * - * For background information on multiplication in finite fields, used for - * the matrix operations in the key schedule, see the book _Contemporary - * Abstract Algebra_ by Joseph A. Gallian, especially chapter 22 in the - * Third Edition. - */ - -#include <crypto/twofish.h> -#include <linux/crypto.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/types.h> - -asmlinkage void twofish_enc_blk(struct crypto_tfm *tfm, u8 *dst, const u8 *src); -asmlinkage void twofish_dec_blk(struct crypto_tfm *tfm, u8 *dst, const u8 *src); - -static void twofish_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) -{ - twofish_enc_blk(tfm, dst, src); -} - -static void twofish_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) -{ - twofish_dec_blk(tfm, dst, src); -} - -static struct crypto_alg alg = { - .cra_name = "twofish", - .cra_driver_name = "twofish-x86_64", - .cra_priority = 200, - .cra_flags = CRYPTO_ALG_TYPE_CIPHER, - .cra_blocksize = TF_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct twofish_ctx), - .cra_alignmask = 3, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), - .cra_u = { - .cipher = { - .cia_min_keysize = TF_MIN_KEY_SIZE, - .cia_max_keysize = TF_MAX_KEY_SIZE, - .cia_setkey = twofish_setkey, - .cia_encrypt = twofish_encrypt, - .cia_decrypt = twofish_decrypt - } - } -}; - -static int __init init(void) -{ - return crypto_register_alg(&alg); -} - -static void __exit fini(void) -{ - crypto_unregister_alg(&alg); -} - -module_init(init); -module_exit(fini); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION ("Twofish Cipher Algorithm, x86_64 asm optimized"); -MODULE_ALIAS("twofish"); diff --git a/arch/x86/crypto/twofish_32.c b/arch/x86/crypto/twofish_glue.c index e3004dfe9c7a..cefaf8b9aa18 100644 --- a/arch/x86/crypto/twofish_32.c +++ b/arch/x86/crypto/twofish_glue.c @@ -1,5 +1,5 @@ /* - * Glue Code for optimized 586 assembler version of TWOFISH + * Glue Code for assembler optimized version of TWOFISH * * Originally Twofish for GPG * By Matthew Skala <mskala@ansuz.sooke.bc.ca>, July 26, 1998 @@ -44,7 +44,6 @@ #include <linux/module.h> #include <linux/types.h> - asmlinkage void twofish_enc_blk(struct crypto_tfm *tfm, u8 *dst, const u8 *src); asmlinkage void twofish_dec_blk(struct crypto_tfm *tfm, u8 *dst, const u8 *src); @@ -60,7 +59,7 @@ static void twofish_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) static struct crypto_alg alg = { .cra_name = "twofish", - .cra_driver_name = "twofish-i586", + .cra_driver_name = "twofish-asm", .cra_priority = 200, .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = TF_BLOCK_SIZE, @@ -93,5 +92,6 @@ module_init(init); module_exit(fini); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION ("Twofish Cipher Algorithm, i586 asm optimized"); +MODULE_DESCRIPTION ("Twofish Cipher Algorithm, asm optimized"); MODULE_ALIAS("twofish"); +MODULE_ALIAS("twofish-asm"); diff --git a/arch/x86/kernel/apic_32.c b/arch/x86/kernel/apic_32.c index edb5108e5d0e..a56c782653be 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 f28ccb588fba..fa6cdee6d303 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 9f530ff43c21..8b4507b8469b 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 4b21d29fb5aa..242e8668dbeb 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 752fb16a817d..753588755fee 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 @@ recurse: 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 05c9936a16cc..d387c770c518 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 29313832df0c..dbd6c1d1b638 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 f634fc715c99..5f3496d01984 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 3f27ea0b9816..ba6d57286f56 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 a6b1490e00c4..ab77f1905469 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 cbac1670c7c3..23a3ac06a23e 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 ee6eba4ecfea..21f6e3c0be18 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 852db2906921..4f4bfd3a88b6 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 4253c4e8849c..c3d1476b6a11 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 944bbcdd2b8d..c8ab79ef4276 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 e452deb80395..f9736fbdab03 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 f2ac914160d1..5e4ab4b37d9f 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 8b919940b2ab..5ccec8aa964b 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/crypto/Kconfig b/crypto/Kconfig index 083d2e1dfc21..c3166a1a5bb6 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -24,10 +24,6 @@ config CRYPTO_ALGAPI help This option provides the API for cryptographic algorithms. -config CRYPTO_ABLKCIPHER - tristate - select CRYPTO_BLKCIPHER - config CRYPTO_AEAD tristate select CRYPTO_ALGAPI @@ -36,6 +32,15 @@ config CRYPTO_BLKCIPHER tristate select CRYPTO_ALGAPI +config CRYPTO_SEQIV + tristate "Sequence Number IV Generator" + select CRYPTO_AEAD + select CRYPTO_BLKCIPHER + help + This IV generator generates an IV based on a sequence number by + xoring it with a salt. This algorithm is mainly useful for CTR + and similar modes. + config CRYPTO_HASH tristate select CRYPTO_ALGAPI @@ -91,7 +96,7 @@ config CRYPTO_SHA1 SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2). config CRYPTO_SHA256 - tristate "SHA256 digest algorithm" + tristate "SHA224 and SHA256 digest algorithm" select CRYPTO_ALGAPI help SHA256 secure hash standard (DFIPS 180-2). @@ -99,6 +104,9 @@ config CRYPTO_SHA256 This version of SHA implements a 256 bit hash with 128 bits of security against collision attacks. + This code also includes SHA-224, a 224 bit hash with 112 bits + of security against collision attacks. + config CRYPTO_SHA512 tristate "SHA384 and SHA512 digest algorithms" select CRYPTO_ALGAPI @@ -195,9 +203,34 @@ config CRYPTO_XTS key size 256, 384 or 512 bits. This implementation currently can't handle a sectorsize which is not a multiple of 16 bytes. +config CRYPTO_CTR + tristate "CTR support" + select CRYPTO_BLKCIPHER + select CRYPTO_SEQIV + select CRYPTO_MANAGER + help + CTR: Counter mode + This block cipher algorithm is required for IPSec. + +config CRYPTO_GCM + tristate "GCM/GMAC support" + select CRYPTO_CTR + select CRYPTO_AEAD + select CRYPTO_GF128MUL + help + Support for Galois/Counter Mode (GCM) and Galois Message + Authentication Code (GMAC). Required for IPSec. + +config CRYPTO_CCM + tristate "CCM support" + select CRYPTO_CTR + select CRYPTO_AEAD + help + Support for Counter with CBC MAC. Required for IPsec. + config CRYPTO_CRYPTD tristate "Software async crypto daemon" - select CRYPTO_ABLKCIPHER + select CRYPTO_BLKCIPHER select CRYPTO_MANAGER help This is a generic software asynchronous crypto daemon that @@ -320,6 +353,7 @@ config CRYPTO_AES_586 tristate "AES cipher algorithms (i586)" depends on (X86 || UML_X86) && !64BIT select CRYPTO_ALGAPI + select CRYPTO_AES help AES cipher algorithms (FIPS-197). AES uses the Rijndael algorithm. @@ -341,6 +375,7 @@ config CRYPTO_AES_X86_64 tristate "AES cipher algorithms (x86_64)" depends on (X86 || UML_X86) && 64BIT select CRYPTO_ALGAPI + select CRYPTO_AES help AES cipher algorithms (FIPS-197). AES uses the Rijndael algorithm. @@ -441,6 +476,46 @@ config CRYPTO_SEED See also: <http://www.kisa.or.kr/kisa/seed/jsp/seed_eng.jsp> +config CRYPTO_SALSA20 + tristate "Salsa20 stream cipher algorithm (EXPERIMENTAL)" + depends on EXPERIMENTAL + select CRYPTO_BLKCIPHER + help + Salsa20 stream cipher algorithm. + + Salsa20 is a stream cipher submitted to eSTREAM, the ECRYPT + Stream Cipher Project. See <http://www.ecrypt.eu.org/stream/> + + The Salsa20 stream cipher algorithm is designed by Daniel J. + Bernstein <djb@cr.yp.to>. See <http://cr.yp.to/snuffle.html> + +config CRYPTO_SALSA20_586 + tristate "Salsa20 stream cipher algorithm (i586) (EXPERIMENTAL)" + depends on (X86 || UML_X86) && !64BIT + depends on EXPERIMENTAL + select CRYPTO_BLKCIPHER + help + Salsa20 stream cipher algorithm. + + Salsa20 is a stream cipher submitted to eSTREAM, the ECRYPT + Stream Cipher Project. See <http://www.ecrypt.eu.org/stream/> + + The Salsa20 stream cipher algorithm is designed by Daniel J. + Bernstein <djb@cr.yp.to>. See <http://cr.yp.to/snuffle.html> + +config CRYPTO_SALSA20_X86_64 + tristate "Salsa20 stream cipher algorithm (x86_64) (EXPERIMENTAL)" + depends on (X86 || UML_X86) && 64BIT + depends on EXPERIMENTAL + select CRYPTO_BLKCIPHER + help + Salsa20 stream cipher algorithm. + + Salsa20 is a stream cipher submitted to eSTREAM, the ECRYPT + Stream Cipher Project. See <http://www.ecrypt.eu.org/stream/> + + The Salsa20 stream cipher algorithm is designed by Daniel J. + Bernstein <djb@cr.yp.to>. See <http://cr.yp.to/snuffle.html> config CRYPTO_DEFLATE tristate "Deflate compression algorithm" @@ -491,6 +566,7 @@ config CRYPTO_TEST tristate "Testing module" depends on m select CRYPTO_ALGAPI + select CRYPTO_AEAD help Quick & dirty crypto test module. @@ -498,10 +574,19 @@ config CRYPTO_AUTHENC tristate "Authenc support" select CRYPTO_AEAD select CRYPTO_MANAGER + select CRYPTO_HASH help Authenc: Combined mode wrapper for IPsec. This is required for IPSec. +config CRYPTO_LZO + tristate "LZO compression algorithm" + select CRYPTO_ALGAPI + select LZO_COMPRESS + select LZO_DECOMPRESS + help + This is the LZO algorithm. + source "drivers/crypto/Kconfig" endif # if CRYPTO diff --git a/crypto/Makefile b/crypto/Makefile index 43c2a0dc9936..48c758379954 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -8,9 +8,14 @@ crypto_algapi-$(CONFIG_PROC_FS) += proc.o crypto_algapi-objs := algapi.o scatterwalk.o $(crypto_algapi-y) obj-$(CONFIG_CRYPTO_ALGAPI) += crypto_algapi.o -obj-$(CONFIG_CRYPTO_ABLKCIPHER) += ablkcipher.o obj-$(CONFIG_CRYPTO_AEAD) += aead.o -obj-$(CONFIG_CRYPTO_BLKCIPHER) += blkcipher.o + +crypto_blkcipher-objs := ablkcipher.o +crypto_blkcipher-objs += blkcipher.o +obj-$(CONFIG_CRYPTO_BLKCIPHER) += crypto_blkcipher.o +obj-$(CONFIG_CRYPTO_BLKCIPHER) += chainiv.o +obj-$(CONFIG_CRYPTO_BLKCIPHER) += eseqiv.o +obj-$(CONFIG_CRYPTO_SEQIV) += seqiv.o crypto_hash-objs := hash.o obj-$(CONFIG_CRYPTO_HASH) += crypto_hash.o @@ -32,6 +37,9 @@ obj-$(CONFIG_CRYPTO_CBC) += cbc.o obj-$(CONFIG_CRYPTO_PCBC) += pcbc.o obj-$(CONFIG_CRYPTO_LRW) += lrw.o obj-$(CONFIG_CRYPTO_XTS) += xts.o +obj-$(CONFIG_CRYPTO_CTR) += ctr.o +obj-$(CONFIG_CRYPTO_GCM) += gcm.o +obj-$(CONFIG_CRYPTO_CCM) += ccm.o obj-$(CONFIG_CRYPTO_CRYPTD) += cryptd.o obj-$(CONFIG_CRYPTO_DES) += des_generic.o obj-$(CONFIG_CRYPTO_FCRYPT) += fcrypt.o @@ -48,10 +56,12 @@ obj-$(CONFIG_CRYPTO_TEA) += tea.o obj-$(CONFIG_CRYPTO_KHAZAD) += khazad.o obj-$(CONFIG_CRYPTO_ANUBIS) += anubis.o obj-$(CONFIG_CRYPTO_SEED) += seed.o +obj-$(CONFIG_CRYPTO_SALSA20) += salsa20_generic.o obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o +obj-$(CONFIG_CRYPTO_LZO) += lzo.o obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c index 2731acb86e7d..3bcb099b4a85 100644 --- a/crypto/ablkcipher.c +++ b/crypto/ablkcipher.c @@ -13,14 +13,18 @@ * */ -#include <crypto/algapi.h> -#include <linux/errno.h> +#include <crypto/internal/skcipher.h> +#include <linux/err.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/rtnetlink.h> +#include <linux/sched.h> #include <linux/slab.h> #include <linux/seq_file.h> +#include "internal.h" + static int setkey_unaligned(struct crypto_ablkcipher *tfm, const u8 *key, unsigned int keylen) { @@ -66,6 +70,16 @@ static unsigned int crypto_ablkcipher_ctxsize(struct crypto_alg *alg, u32 type, return alg->cra_ctxsize; } +int skcipher_null_givencrypt(struct skcipher_givcrypt_request *req) +{ + return crypto_ablkcipher_encrypt(&req->creq); +} + +int skcipher_null_givdecrypt(struct skcipher_givcrypt_request *req) +{ + return crypto_ablkcipher_decrypt(&req->creq); +} + static int crypto_init_ablkcipher_ops(struct crypto_tfm *tfm, u32 type, u32 mask) { @@ -78,6 +92,11 @@ static int crypto_init_ablkcipher_ops(struct crypto_tfm *tfm, u32 type, crt->setkey = setkey; crt->encrypt = alg->encrypt; crt->decrypt = alg->decrypt; + if (!alg->ivsize) { + crt->givencrypt = skcipher_null_givencrypt; + crt->givdecrypt = skcipher_null_givdecrypt; + } + crt->base = __crypto_ablkcipher_cast(tfm); crt->ivsize = alg->ivsize; return 0; @@ -90,10 +109,13 @@ static void crypto_ablkcipher_show(struct seq_file *m, struct crypto_alg *alg) struct ablkcipher_alg *ablkcipher = &alg->cra_ablkcipher; seq_printf(m, "type : ablkcipher\n"); + seq_printf(m, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ? + "yes" : "no"); seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); seq_printf(m, "min keysize : %u\n", ablkcipher->min_keysize); seq_printf(m, "max keysize : %u\n", ablkcipher->max_keysize); seq_printf(m, "ivsize : %u\n", ablkcipher->ivsize); + seq_printf(m, "geniv : %s\n", ablkcipher->geniv ?: "<default>"); } const struct crypto_type crypto_ablkcipher_type = { @@ -105,5 +127,220 @@ const struct crypto_type crypto_ablkcipher_type = { }; EXPORT_SYMBOL_GPL(crypto_ablkcipher_type); +static int no_givdecrypt(struct skcipher_givcrypt_request *req) +{ + return -ENOSYS; +} + +static int crypto_init_givcipher_ops(struct crypto_tfm *tfm, u32 type, + u32 mask) +{ + struct ablkcipher_alg *alg = &tfm->__crt_alg->cra_ablkcipher; + struct ablkcipher_tfm *crt = &tfm->crt_ablkcipher; + + if (alg->ivsize > PAGE_SIZE / 8) + return -EINVAL; + + crt->setkey = tfm->__crt_alg->cra_flags & CRYPTO_ALG_GENIV ? + alg->setkey : setkey; + crt->encrypt = alg->encrypt; + crt->decrypt = alg->decrypt; + crt->givencrypt = alg->givencrypt; + crt->givdecrypt = alg->givdecrypt ?: no_givdecrypt; + crt->base = __crypto_ablkcipher_cast(tfm); + crt->ivsize = alg->ivsize; + + return 0; +} + +static void crypto_givcipher_show(struct seq_file *m, struct crypto_alg *alg) + __attribute__ ((unused)); +static void crypto_givcipher_show(struct seq_file *m, struct crypto_alg *alg) +{ + struct ablkcipher_alg *ablkcipher = &alg->cra_ablkcipher; + + seq_printf(m, "type : givcipher\n"); + seq_printf(m, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ? + "yes" : "no"); + seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); + seq_printf(m, "min keysize : %u\n", ablkcipher->min_keysize); + seq_printf(m, "max keysize : %u\n", ablkcipher->max_keysize); + seq_printf(m, "ivsize : %u\n", ablkcipher->ivsize); + seq_printf(m, "geniv : %s\n", ablkcipher->geniv ?: "<built-in>"); +} + +const struct crypto_type crypto_givcipher_type = { + .ctxsize = crypto_ablkcipher_ctxsize, + .init = crypto_init_givcipher_ops, +#ifdef CONFIG_PROC_FS + .show = crypto_givcipher_show, +#endif +}; +EXPORT_SYMBOL_GPL(crypto_givcipher_type); + +const char *crypto_default_geniv(const struct crypto_alg *alg) +{ + return alg->cra_flags & CRYPTO_ALG_ASYNC ? "eseqiv" : "chainiv"; +} + +static int crypto_givcipher_default(struct crypto_alg *alg, u32 type, u32 mask) +{ + struct rtattr *tb[3]; + struct { + struct rtattr attr; + struct crypto_attr_type data; + } ptype; + struct { + struct rtattr attr; + struct crypto_attr_alg data; + } palg; + struct crypto_template *tmpl; + struct crypto_instance *inst; + struct crypto_alg *larval; + const char *geniv; + int err; + + larval = crypto_larval_lookup(alg->cra_driver_name, + CRYPTO_ALG_TYPE_GIVCIPHER, + CRYPTO_ALG_TYPE_MASK); + err = PTR_ERR(larval); + if (IS_ERR(larval)) + goto out; + + err = -EAGAIN; + if (!crypto_is_larval(larval)) + goto drop_larval; + + ptype.attr.rta_len = sizeof(ptype); + ptype.attr.rta_type = CRYPTOA_TYPE; + ptype.data.type = type | CRYPTO_ALG_GENIV; + /* GENIV tells the template that we're making a default geniv. */ + ptype.data.mask = mask | CRYPTO_ALG_GENIV; + tb[0] = &ptype.attr; + + palg.attr.rta_len = sizeof(palg); + palg.attr.rta_type = CRYPTOA_ALG; + /* Must use the exact name to locate ourselves. */ + memcpy(palg.data.name, alg->cra_driver_name, CRYPTO_MAX_ALG_NAME); + tb[1] = &palg.attr; + + tb[2] = NULL; + + if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) == + CRYPTO_ALG_TYPE_BLKCIPHER) + geniv = alg->cra_blkcipher.geniv; + else + geniv = alg->cra_ablkcipher.geniv; + + if (!geniv) + geniv = crypto_default_geniv(alg); + + tmpl = crypto_lookup_template(geniv); + err = -ENOENT; + if (!tmpl) + goto kill_larval; + + inst = tmpl->alloc(tb); + err = PTR_ERR(inst); + if (IS_ERR(inst)) + goto put_tmpl; + + if ((err = crypto_register_instance(tmpl, inst))) { + tmpl->free(inst); + goto put_tmpl; + } + + /* Redo the lookup to use the instance we just registered. */ + err = -EAGAIN; + +put_tmpl: + crypto_tmpl_put(tmpl); +kill_larval: + crypto_larval_kill(larval); +drop_larval: + crypto_mod_put(larval); +out: + crypto_mod_put(alg); + return err; +} + +static struct crypto_alg *crypto_lookup_skcipher(const char *name, u32 type, + u32 mask) +{ + struct crypto_alg *alg; + + alg = crypto_alg_mod_lookup(name, type, mask); + if (IS_ERR(alg)) + return alg; + + if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) == + CRYPTO_ALG_TYPE_GIVCIPHER) + return alg; + + if (!((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) == + CRYPTO_ALG_TYPE_BLKCIPHER ? alg->cra_blkcipher.ivsize : + alg->cra_ablkcipher.ivsize)) + return alg; + + return ERR_PTR(crypto_givcipher_default(alg, type, mask)); +} + +int crypto_grab_skcipher(struct crypto_skcipher_spawn *spawn, const char *name, + u32 type, u32 mask) +{ + struct crypto_alg *alg; + int err; + + type = crypto_skcipher_type(type); + mask = crypto_skcipher_mask(mask); + + alg = crypto_lookup_skcipher(name, type, mask); + if (IS_ERR(alg)) + return PTR_ERR(alg); + + err = crypto_init_spawn(&spawn->base, alg, spawn->base.inst, mask); + crypto_mod_put(alg); + return err; +} +EXPORT_SYMBOL_GPL(crypto_grab_skcipher); + +struct crypto_ablkcipher *crypto_alloc_ablkcipher(const char *alg_name, + u32 type, u32 mask) +{ + struct crypto_tfm *tfm; + int err; + + type = crypto_skcipher_type(type); + mask = crypto_skcipher_mask(mask); + + for (;;) { + struct crypto_alg *alg; + + alg = crypto_lookup_skcipher(alg_name, type, mask); + if (IS_ERR(alg)) { + err = PTR_ERR(alg); + goto err; + } + + tfm = __crypto_alloc_tfm(alg, type, mask); + if (!IS_ERR(tfm)) + return __crypto_ablkcipher_cast(tfm); + + crypto_mod_put(alg); + err = PTR_ERR(tfm); + +err: + if (err != -EAGAIN) + break; + if (signal_pending(current)) { + err = -EINTR; + break; + } + } + + return ERR_PTR(err); +} +EXPORT_SYMBOL_GPL(crypto_alloc_ablkcipher); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Asynchronous block chaining cipher type"); diff --git a/crypto/aead.c b/crypto/aead.c index 84a3501fb478..3a6f3f52c7c7 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -12,14 +12,17 @@ * */ -#include <crypto/algapi.h> -#include <linux/errno.h> +#include <crypto/internal/aead.h> +#include <linux/err.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/rtnetlink.h> #include <linux/slab.h> #include <linux/seq_file.h> +#include "internal.h" + static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key, unsigned int keylen) { @@ -53,25 +56,54 @@ static int setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen) return aead->setkey(tfm, key, keylen); } +int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize) +{ + struct aead_tfm *crt = crypto_aead_crt(tfm); + int err; + + if (authsize > crypto_aead_alg(tfm)->maxauthsize) + return -EINVAL; + + if (crypto_aead_alg(tfm)->setauthsize) { + err = crypto_aead_alg(tfm)->setauthsize(crt->base, authsize); + if (err) + return err; + } + + crypto_aead_crt(crt->base)->authsize = authsize; + crt->authsize = authsize; + return 0; +} +EXPORT_SYMBOL_GPL(crypto_aead_setauthsize); + static unsigned int crypto_aead_ctxsize(struct crypto_alg *alg, u32 type, u32 mask) { return alg->cra_ctxsize; } +static int no_givcrypt(struct aead_givcrypt_request *req) +{ + return -ENOSYS; +} + static int crypto_init_aead_ops(struct crypto_tfm *tfm, u32 type, u32 mask) { struct aead_alg *alg = &tfm->__crt_alg->cra_aead; struct aead_tfm *crt = &tfm->crt_aead; - if (max(alg->authsize, alg->ivsize) > PAGE_SIZE / 8) + if (max(alg->maxauthsize, alg->ivsize) > PAGE_SIZE / 8) return -EINVAL; - crt->setkey = setkey; + crt->setkey = tfm->__crt_alg->cra_flags & CRYPTO_ALG_GENIV ? + alg->setkey : setkey; crt->encrypt = alg->encrypt; crt->decrypt = alg->decrypt; + crt->givencrypt = alg->givencrypt ?: no_givcrypt; + crt->givdecrypt = alg->givdecrypt ?: no_givcrypt; + crt->base = __crypto_aead_cast(tfm); crt->ivsize = alg->ivsize; - crt->authsize = alg->authsize; + crt->authsize = alg->maxauthsize; return 0; } @@ -83,9 +115,12 @@ static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg) struct aead_alg *aead = &alg->cra_aead; seq_printf(m, "type : aead\n"); + seq_printf(m, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ? + "yes" : "no"); seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); seq_printf(m, "ivsize : %u\n", aead->ivsize); - seq_printf(m, "authsize : %u\n", aead->authsize); + seq_printf(m, "maxauthsize : %u\n", aead->maxauthsize); + seq_printf(m, "geniv : %s\n", aead->geniv ?: "<built-in>"); } const struct crypto_type crypto_aead_type = { @@ -97,5 +132,358 @@ const struct crypto_type crypto_aead_type = { }; EXPORT_SYMBOL_GPL(crypto_aead_type); +static int aead_null_givencrypt(struct aead_givcrypt_request *req) +{ + return crypto_aead_encrypt(&req->areq); +} + +static int aead_null_givdecrypt(struct aead_givcrypt_request *req) +{ + return crypto_aead_decrypt(&req->areq); +} + +static int crypto_init_nivaead_ops(struct crypto_tfm *tfm, u32 type, u32 mask) +{ + struct aead_alg *alg = &tfm->__crt_alg->cra_aead; + struct aead_tfm *crt = &tfm->crt_aead; + + if (max(alg->maxauthsize, alg->ivsize) > PAGE_SIZE / 8) + return -EINVAL; + + crt->setkey = setkey; + crt->encrypt = alg->encrypt; + crt->decrypt = alg->decrypt; + if (!alg->ivsize) { + crt->givencrypt = aead_null_givencrypt; + crt->givdecrypt = aead_null_givdecrypt; + } + crt->base = __crypto_aead_cast(tfm); + crt->ivsize = alg->ivsize; + crt->authsize = alg->maxauthsize; + + return 0; +} + +static void crypto_nivaead_show(struct seq_file *m, struct crypto_alg *alg) + __attribute__ ((unused)); +static void crypto_nivaead_show(struct seq_file *m, struct crypto_alg *alg) +{ + struct aead_alg *aead = &alg->cra_aead; + + seq_printf(m, "type : nivaead\n"); + seq_printf(m, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ? + "yes" : "no"); + seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); + seq_printf(m, "ivsize : %u\n", aead->ivsize); + seq_printf(m, "maxauthsize : %u\n", aead->maxauthsize); + seq_printf(m, "geniv : %s\n", aead->geniv); +} + +const struct crypto_type crypto_nivaead_type = { + .ctxsize = crypto_aead_ctxsize, + .init = crypto_init_nivaead_ops, +#ifdef CONFIG_PROC_FS + .show = crypto_nivaead_show, +#endif +}; +EXPORT_SYMBOL_GPL(crypto_nivaead_type); + +static int crypto_grab_nivaead(struct crypto_aead_spawn *spawn, + const char *name, u32 type, u32 mask) +{ + struct crypto_alg *alg; + int err; + + type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV); + type |= CRYPTO_ALG_TYPE_AEAD; + mask |= CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV; + + alg = crypto_alg_mod_lookup(name, type, mask); + if (IS_ERR(alg)) + return PTR_ERR(alg); + + err = crypto_init_spawn(&spawn->base, alg, spawn->base.inst, mask); + crypto_mod_put(alg); + return err; +} + +struct crypto_instance *aead_geniv_alloc(struct crypto_template *tmpl, + struct rtattr **tb, u32 type, + u32 mask) +{ + const char *name; + struct crypto_aead_spawn *spawn; + struct crypto_attr_type *algt; + struct crypto_instance *inst; + struct crypto_alg *alg; + int err; + + algt = crypto_get_attr_type(tb); + err = PTR_ERR(algt); + if (IS_ERR(algt)) + return ERR_PTR(err); + + if ((algt->type ^ (CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_GENIV)) & + algt->mask) + return ERR_PTR(-EINVAL); + + name = crypto_attr_alg_name(tb[1]); + err = PTR_ERR(name); + if (IS_ERR(name)) + return ERR_PTR(err); + + inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL); + if (!inst) + return ERR_PTR(-ENOMEM); + + spawn = crypto_instance_ctx(inst); + + /* Ignore async algorithms if necessary. */ + mask |= crypto_requires_sync(algt->type, algt->mask); + + crypto_set_aead_spawn(spawn, inst); + err = crypto_grab_nivaead(spawn, name, type, mask); + if (err) + goto err_free_inst; + + alg = crypto_aead_spawn_alg(spawn); + + err = -EINVAL; + if (!alg->cra_aead.ivsize) + goto err_drop_alg; + + /* + * This is only true if we're constructing an algorithm with its + * default IV generator. For the default generator we elide the + * template name and double-check the IV generator. + */ + if (algt->mask & CRYPTO_ALG_GENIV) { + if (strcmp(tmpl->name, alg->cra_aead.geniv)) + goto err_drop_alg; + + memcpy(inst->alg.cra_name, alg->cra_name, CRYPTO_MAX_ALG_NAME); + memcpy(inst->alg.cra_driver_name, alg->cra_driver_name, + CRYPTO_MAX_ALG_NAME); + } else { + err = -ENAMETOOLONG; + if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, + "%s(%s)", tmpl->name, alg->cra_name) >= + CRYPTO_MAX_ALG_NAME) + goto err_drop_alg; + if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, + "%s(%s)", tmpl->name, alg->cra_driver_name) >= + CRYPTO_MAX_ALG_NAME) + goto err_drop_alg; + } + + inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_GENIV; + inst->alg.cra_flags |= alg->cra_flags & CRYPTO_ALG_ASYNC; + inst->alg.cra_priority = alg->cra_priority; + inst->alg.cra_blocksize = alg->cra_blocksize; + inst->alg.cra_alignmask = alg->cra_alignmask; + inst->alg.cra_type = &crypto_aead_type; + + inst->alg.cra_aead.ivsize = alg->cra_aead.ivsize; + inst->alg.cra_aead.maxauthsize = alg->cra_aead.maxauthsize; + inst->alg.cra_aead.geniv = alg->cra_aead.geniv; + + inst->alg.cra_aead.setkey = alg->cra_aead.setkey; + inst->alg.cra_aead.setauthsize = alg->cra_aead.setauthsize; + inst->alg.cra_aead.encrypt = alg->cra_aead.encrypt; + inst->alg.cra_aead.decrypt = alg->cra_aead.decrypt; + +out: + return inst; + +err_drop_alg: + crypto_drop_aead(spawn); +err_free_inst: + kfree(inst); + inst = ERR_PTR(err); + goto out; +} +EXPORT_SYMBOL_GPL(aead_geniv_alloc); + +void aead_geniv_free(struct crypto_instance *inst) +{ + crypto_drop_aead(crypto_instance_ctx(inst)); + kfree(inst); +} +EXPORT_SYMBOL_GPL(aead_geniv_free); + +int aead_geniv_init(struct crypto_tfm *tfm) +{ + struct crypto_instance *inst = (void *)tfm->__crt_alg; + struct crypto_aead *aead; + + aead = crypto_spawn_aead(crypto_instance_ctx(inst)); + if (IS_ERR(aead)) + return PTR_ERR(aead); + + tfm->crt_aead.base = aead; + tfm->crt_aead.reqsize += crypto_aead_reqsize(aead); + + return 0; +} +EXPORT_SYMBOL_GPL(aead_geniv_init); + +void aead_geniv_exit(struct crypto_tfm *tfm) +{ + crypto_free_aead(tfm->crt_aead.base); +} +EXPORT_SYMBOL_GPL(aead_geniv_exit); + +static int crypto_nivaead_default(struct crypto_alg *alg, u32 type, u32 mask) +{ + struct rtattr *tb[3]; + struct { + struct rtattr attr; + struct crypto_attr_type data; + } ptype; + struct { + struct rtattr attr; + struct crypto_attr_alg data; + } palg; + struct crypto_template *tmpl; + struct crypto_instance *inst; + struct crypto_alg *larval; + const char *geniv; + int err; + + larval = crypto_larval_lookup(alg->cra_driver_name, + CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_GENIV, + CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV); + err = PTR_ERR(larval); + if (IS_ERR(larval)) + goto out; + + err = -EAGAIN; + if (!crypto_is_larval(larval)) + goto drop_larval; + + ptype.attr.rta_len = sizeof(ptype); + ptype.attr.rta_type = CRYPTOA_TYPE; + ptype.data.type = type | CRYPTO_ALG_GENIV; + /* GENIV tells the template that we're making a default geniv. */ + ptype.data.mask = mask | CRYPTO_ALG_GENIV; + tb[0] = &ptype.attr; + + palg.attr.rta_len = sizeof(palg); + palg.attr.rta_type = CRYPTOA_ALG; + /* Must use the exact name to locate ourselves. */ + memcpy(palg.data.name, alg->cra_driver_name, CRYPTO_MAX_ALG_NAME); + tb[1] = &palg.attr; + + tb[2] = NULL; + + geniv = alg->cra_aead.geniv; + + tmpl = crypto_lookup_template(geniv); + err = -ENOENT; + if (!tmpl) + goto kill_larval; + + inst = tmpl->alloc(tb); + err = PTR_ERR(inst); + if (IS_ERR(inst)) + goto put_tmpl; + + if ((err = crypto_register_instance(tmpl, inst))) { + tmpl->free(inst); + goto put_tmpl; + } + + /* Redo the lookup to use the instance we just registered. */ + err = -EAGAIN; + +put_tmpl: + crypto_tmpl_put(tmpl); +kill_larval: + crypto_larval_kill(larval); +drop_larval: + crypto_mod_put(larval); +out: + crypto_mod_put(alg); + return err; +} + +static struct crypto_alg *crypto_lookup_aead(const char *name, u32 type, + u32 mask) +{ + struct crypto_alg *alg; + + alg = crypto_alg_mod_lookup(name, type, mask); + if (IS_ERR(alg)) + return alg; + + if (alg->cra_type == &crypto_aead_type) + return alg; + + if (!alg->cra_aead.ivsize) + return alg; + + return ERR_PTR(crypto_nivaead_default(alg, type, mask)); +} + +int crypto_grab_aead(struct crypto_aead_spawn *spawn, const char *name, + u32 type, u32 mask) +{ + struct crypto_alg *alg; + int err; + + type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV); + type |= CRYPTO_ALG_TYPE_AEAD; + mask &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV); + mask |= CRYPTO_ALG_TYPE_MASK; + + alg = crypto_lookup_aead(name, type, mask); + if (IS_ERR(alg)) + return PTR_ERR(alg); + + err = crypto_init_spawn(&spawn->base, alg, spawn->base.inst, mask); + crypto_mod_put(alg); + return err; +} +EXPORT_SYMBOL_GPL(crypto_grab_aead); + +struct crypto_aead *crypto_alloc_aead(const char *alg_name, u32 type, u32 mask) +{ + struct crypto_tfm *tfm; + int err; + + type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV); + type |= CRYPTO_ALG_TYPE_AEAD; + mask &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV); + mask |= CRYPTO_ALG_TYPE_MASK; + + for (;;) { + struct crypto_alg *alg; + + alg = crypto_lookup_aead(alg_name, type, mask); + if (IS_ERR(alg)) { + err = PTR_ERR(alg); + goto err; + } + + tfm = __crypto_alloc_tfm(alg, type, mask); + if (!IS_ERR(tfm)) + return __crypto_aead_cast(tfm); + + crypto_mod_put(alg); + err = PTR_ERR(tfm); + +err: + if (err != -EAGAIN) + break; + if (signal_pending(current)) { + err = -EINTR; + break; + } + } + + return ERR_PTR(err); +} +EXPORT_SYMBOL_GPL(crypto_alloc_aead); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Authenticated Encryption with Associated Data (AEAD)"); diff --git a/crypto/aes_generic.c b/crypto/aes_generic.c index 9401dca85e87..cf30af74480f 100644 --- a/crypto/aes_generic.c +++ b/crypto/aes_generic.c @@ -47,11 +47,7 @@ * --------------------------------------------------------------------------- */ -/* Some changes from the Gladman version: - s/RIJNDAEL(e_key)/E_KEY/g - s/RIJNDAEL(d_key)/D_KEY/g -*/ - +#include <crypto/aes.h> #include <linux/module.h> #include <linux/init.h> #include <linux/types.h> @@ -59,88 +55,46 @@ #include <linux/crypto.h> #include <asm/byteorder.h> -#define AES_MIN_KEY_SIZE 16 -#define AES_MAX_KEY_SIZE 32 - -#define AES_BLOCK_SIZE 16 - -/* - * #define byte(x, nr) ((unsigned char)((x) >> (nr*8))) - */ -static inline u8 -byte(const u32 x, const unsigned n) +static inline u8 byte(const u32 x, const unsigned n) { return x >> (n << 3); } -struct aes_ctx { - int key_length; - u32 buf[120]; -}; - -#define E_KEY (&ctx->buf[0]) -#define D_KEY (&ctx->buf[60]) - static u8 pow_tab[256] __initdata; static u8 log_tab[256] __initdata; static u8 sbx_tab[256] __initdata; static u8 isb_tab[256] __initdata; static u32 rco_tab[10]; -static u32 ft_tab[4][256]; -static u32 it_tab[4][256]; -static u32 fl_tab[4][256]; -static u32 il_tab[4][256]; +u32 crypto_ft_tab[4][256]; +u32 crypto_fl_tab[4][256]; +u32 crypto_it_tab[4][256]; +u32 crypto_il_tab[4][256]; -static inline u8 __init -f_mult (u8 a, u8 b) +EXPORT_SYMBOL_GPL(crypto_ft_tab); +EXPORT_SYMBOL_GPL(crypto_fl_tab); +EXPORT_SYMBOL_GPL(crypto_it_tab); +EXPORT_SYMBOL_GPL(crypto_il_tab); + +static inline u8 __init f_mult(u8 a, u8 b) { u8 aa = log_tab[a], cc = aa + log_tab[b]; return pow_tab[cc + (cc < aa ? 1 : 0)]; } -#define ff_mult(a,b) (a && b ? f_mult(a, b) : 0) - -#define f_rn(bo, bi, n, k) \ - bo[n] = ft_tab[0][byte(bi[n],0)] ^ \ - ft_tab[1][byte(bi[(n + 1) & 3],1)] ^ \ - ft_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ - ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n) - -#define i_rn(bo, bi, n, k) \ - bo[n] = it_tab[0][byte(bi[n],0)] ^ \ - it_tab[1][byte(bi[(n + 3) & 3],1)] ^ \ - it_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ - it_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) - -#define ls_box(x) \ - ( fl_tab[0][byte(x, 0)] ^ \ - fl_tab[1][byte(x, 1)] ^ \ - fl_tab[2][byte(x, 2)] ^ \ - fl_tab[3][byte(x, 3)] ) - -#define f_rl(bo, bi, n, k) \ - bo[n] = fl_tab[0][byte(bi[n],0)] ^ \ - fl_tab[1][byte(bi[(n + 1) & 3],1)] ^ \ - fl_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ - fl_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n) - -#define i_rl(bo, bi, n, k) \ - bo[n] = il_tab[0][byte(bi[n],0)] ^ \ - il_tab[1][byte(bi[(n + 3) & 3],1)] ^ \ - il_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ - il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) - -static void __init -gen_tabs (void) +#define ff_mult(a, b) (a && b ? f_mult(a, b) : 0) + +static void __init gen_tabs(void) { u32 i, t; u8 p, q; - /* log and power tables for GF(2**8) finite field with - 0x011b as modular polynomial - the simplest primitive - root is 0x03, used here to generate the tables */ + /* + * log and power tables for GF(2**8) finite field with + * 0x011b as modular polynomial - the simplest primitive + * root is 0x03, used here to generate the tables + */ for (i = 0, p = 1; i < 256; ++i) { pow_tab[i] = (u8) p; @@ -169,92 +123,119 @@ gen_tabs (void) p = sbx_tab[i]; t = p; - fl_tab[0][i] = t; - fl_tab[1][i] = rol32(t, 8); - fl_tab[2][i] = rol32(t, 16); - fl_tab[3][i] = rol32(t, 24); + crypto_fl_tab[0][i] = t; + crypto_fl_tab[1][i] = rol32(t, 8); + crypto_fl_tab[2][i] = rol32(t, 16); + crypto_fl_tab[3][i] = rol32(t, 24); - t = ((u32) ff_mult (2, p)) | + t = ((u32) ff_mult(2, p)) | ((u32) p << 8) | - ((u32) p << 16) | ((u32) ff_mult (3, p) << 24); + ((u32) p << 16) | ((u32) ff_mult(3, p) << 24); - ft_tab[0][i] = t; - ft_tab[1][i] = rol32(t, 8); - ft_tab[2][i] = rol32(t, 16); - ft_tab[3][i] = rol32(t, 24); + crypto_ft_tab[0][i] = t; + crypto_ft_tab[1][i] = rol32(t, 8); + crypto_ft_tab[2][i] = rol32(t, 16); + crypto_ft_tab[3][i] = rol32(t, 24); p = isb_tab[i]; t = p; - il_tab[0][i] = t; - il_tab[1][i] = rol32(t, 8); - il_tab[2][i] = rol32(t, 16); - il_tab[3][i] = rol32(t, 24); - - t = ((u32) ff_mult (14, p)) | - ((u32) ff_mult (9, p) << 8) | - ((u32) ff_mult (13, p) << 16) | - ((u32) ff_mult (11, p) << 24); - - it_tab[0][i] = t; - it_tab[1][i] = rol32(t, 8); - it_tab[2][i] = rol32(t, 16); - it_tab[3][i] = rol32(t, 24); + crypto_il_tab[0][i] = t; + crypto_il_tab[1][i] = rol32(t, 8); + crypto_il_tab[2][i] = rol32(t, 16); + crypto_il_tab[3][i] = rol32(t, 24); + + t = ((u32) ff_mult(14, p)) | + ((u32) ff_mult(9, p) << 8) | + ((u32) ff_mult(13, p) << 16) | + ((u32) ff_mult(11, p) << 24); + + crypto_it_tab[0][i] = t; + crypto_it_tab[1][i] = rol32(t, 8); + crypto_it_tab[2][i] = rol32(t, 16); + crypto_it_tab[3][i] = rol32(t, 24); } } -#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b) - -#define imix_col(y,x) \ - u = star_x(x); \ - v = star_x(u); \ - w = star_x(v); \ - t = w ^ (x); \ - (y) = u ^ v ^ w; \ - (y) ^= ror32(u ^ t, 8) ^ \ - ror32(v ^ t, 16) ^ \ - ror32(t,24) - /* initialise the key schedule from the user supplied key */ -#define loop4(i) \ -{ t = ror32(t, 8); t = ls_box(t) ^ rco_tab[i]; \ - t ^= E_KEY[4 * i]; E_KEY[4 * i + 4] = t; \ - t ^= E_KEY[4 * i + 1]; E_KEY[4 * i + 5] = t; \ - t ^= E_KEY[4 * i + 2]; E_KEY[4 * i + 6] = t; \ - t ^= E_KEY[4 * i + 3]; E_KEY[4 * i + 7] = t; \ -} - -#define loop6(i) \ -{ t = ror32(t, 8); t = ls_box(t) ^ rco_tab[i]; \ - t ^= E_KEY[6 * i]; E_KEY[6 * i + 6] = t; \ - t ^= E_KEY[6 * i + 1]; E_KEY[6 * i + 7] = t; \ - t ^= E_KEY[6 * i + 2]; E_KEY[6 * i + 8] = t; \ - t ^= E_KEY[6 * i + 3]; E_KEY[6 * i + 9] = t; \ - t ^= E_KEY[6 * i + 4]; E_KEY[6 * i + 10] = t; \ - t ^= E_KEY[6 * i + 5]; E_KEY[6 * i + 11] = t; \ -} - -#define loop8(i) \ -{ t = ror32(t, 8); ; t = ls_box(t) ^ rco_tab[i]; \ - t ^= E_KEY[8 * i]; E_KEY[8 * i + 8] = t; \ - t ^= E_KEY[8 * i + 1]; E_KEY[8 * i + 9] = t; \ - t ^= E_KEY[8 * i + 2]; E_KEY[8 * i + 10] = t; \ - t ^= E_KEY[8 * i + 3]; E_KEY[8 * i + 11] = t; \ - t = E_KEY[8 * i + 4] ^ ls_box(t); \ - E_KEY[8 * i + 12] = t; \ - t ^= E_KEY[8 * i + 5]; E_KEY[8 * i + 13] = t; \ - t ^= E_KEY[8 * i + 6]; E_KEY[8 * i + 14] = t; \ - t ^= E_KEY[8 * i + 7]; E_KEY[8 * i + 15] = t; \ -} +#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b) -static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, - unsigned int key_len) +#define imix_col(y,x) do { \ + u = star_x(x); \ + v = star_x(u); \ + w = star_x(v); \ + t = w ^ (x); \ + (y) = u ^ v ^ w; \ + (y) ^= ror32(u ^ t, 8) ^ \ + ror32(v ^ t, 16) ^ \ + ror32(t, 24); \ +} while (0) + +#define ls_box(x) \ + crypto_fl_tab[0][byte(x, 0)] ^ \ + crypto_fl_tab[1][byte(x, 1)] ^ \ + crypto_fl_tab[2][byte(x, 2)] ^ \ + crypto_fl_tab[3][byte(x, 3)] + +#define loop4(i) do { \ + t = ror32(t, 8); \ + t = ls_box(t) ^ rco_tab[i]; \ + t ^= ctx->key_enc[4 * i]; \ + ctx->key_enc[4 * i + 4] = t; \ + t ^= ctx->key_enc[4 * i + 1]; \ + ctx->key_enc[4 * i + 5] = t; \ + t ^= ctx->key_enc[4 * i + 2]; \ + ctx->key_enc[4 * i + 6] = t; \ + t ^= ctx->key_enc[4 * i + 3]; \ + ctx->key_enc[4 * i + 7] = t; \ +} while (0) + +#define loop6(i) do { \ + t = ror32(t, 8); \ + t = ls_box(t) ^ rco_tab[i]; \ + t ^= ctx->key_enc[6 * i]; \ + ctx->key_enc[6 * i + 6] = t; \ + t ^= ctx->key_enc[6 * i + 1]; \ + ctx->key_enc[6 * i + 7] = t; \ + t ^= ctx->key_enc[6 * i + 2]; \ + ctx->key_enc[6 * i + 8] = t; \ + t ^= ctx->key_enc[6 * i + 3]; \ + ctx->key_enc[6 * i + 9] = t; \ + t ^= ctx->key_enc[6 * i + 4]; \ + ctx->key_enc[6 * i + 10] = t; \ + t ^= ctx->key_enc[6 * i + 5]; \ + ctx->key_enc[6 * i + 11] = t; \ +} while (0) + +#define loop8(i) do { \ + t = ror32(t, 8); \ + t = ls_box(t) ^ rco_tab[i]; \ + t ^= ctx->key_enc[8 * i]; \ + ctx->key_enc[8 * i + 8] = t; \ + t ^= ctx->key_enc[8 * i + 1]; \ + ctx->key_enc[8 * i + 9] = t; \ + t ^= ctx->key_enc[8 * i + 2]; \ + ctx->key_enc[8 * i + 10] = t; \ + t ^= ctx->key_enc[8 * i + 3]; \ + ctx->key_enc[8 * i + 11] = t; \ + t = ctx->key_enc[8 * i + 4] ^ ls_box(t); \ + ctx->key_enc[8 * i + 12] = t; \ + t ^= ctx->key_enc[8 * i + 5]; \ + ctx->key_enc[8 * i + 13] = t; \ + t ^= ctx->key_enc[8 * i + 6]; \ + ctx->key_enc[8 * i + 14] = t; \ + t ^= ctx->key_enc[8 * i + 7]; \ + ctx->key_enc[8 * i + 15] = t; \ +} while (0) + +int crypto_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, + unsigned int key_len) { - struct aes_ctx *ctx = crypto_tfm_ctx(tfm); + struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm); const __le32 *key = (const __le32 *)in_key; u32 *flags = &tfm->crt_flags; - u32 i, t, u, v, w; + u32 i, t, u, v, w, j; if (key_len % 8) { *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; @@ -263,95 +244,113 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, ctx->key_length = key_len; - E_KEY[0] = le32_to_cpu(key[0]); - E_KEY[1] = le32_to_cpu(key[1]); - E_KEY[2] = le32_to_cpu(key[2]); - E_KEY[3] = le32_to_cpu(key[3]); + ctx->key_dec[key_len + 24] = ctx->key_enc[0] = le32_to_cpu(key[0]); + ctx->key_dec[key_len + 25] = ctx->key_enc[1] = le32_to_cpu(key[1]); + ctx->key_dec[key_len + 26] = ctx->key_enc[2] = le32_to_cpu(key[2]); + ctx->key_dec[key_len + 27] = ctx->key_enc[3] = le32_to_cpu(key[3]); switch (key_len) { case 16: - t = E_KEY[3]; + t = ctx->key_enc[3]; for (i = 0; i < 10; ++i) - loop4 (i); + loop4(i); break; case 24: - E_KEY[4] = le32_to_cpu(key[4]); - t = E_KEY[5] = le32_to_cpu(key[5]); + ctx->key_enc[4] = le32_to_cpu(key[4]); + t = ctx->key_enc[5] = le32_to_cpu(key[5]); for (i = 0; i < 8; ++i) - loop6 (i); + loop6(i); break; case 32: - E_KEY[4] = le32_to_cpu(key[4]); - E_KEY[5] = le32_to_cpu(key[5]); - E_KEY[6] = le32_to_cpu(key[6]); - t = E_KEY[7] = le32_to_cpu(key[7]); + ctx->key_enc[4] = le32_to_cpu(key[4]); + ctx->key_enc[5] = le32_to_cpu(key[5]); + ctx->key_enc[6] = le32_to_cpu(key[6]); + t = ctx->key_enc[7] = le32_to_cpu(key[7]); for (i = 0; i < 7; ++i) - loop8 (i); + loop8(i); break; } - D_KEY[0] = E_KEY[0]; - D_KEY[1] = E_KEY[1]; - D_KEY[2] = E_KEY[2]; - D_KEY[3] = E_KEY[3]; + ctx->key_dec[0] = ctx->key_enc[key_len + 24]; + ctx->key_dec[1] = ctx->key_enc[key_len + 25]; + ctx->key_dec[2] = ctx->key_enc[key_len + 26]; + ctx->key_dec[3] = ctx->key_enc[key_len + 27]; for (i = 4; i < key_len + 24; ++i) { - imix_col (D_KEY[i], E_KEY[i]); + j = key_len + 24 - (i & ~3) + (i & 3); + imix_col(ctx->key_dec[j], ctx->key_enc[i]); } - return 0; } +EXPORT_SYMBOL_GPL(crypto_aes_set_key); /* encrypt a block of text */ -#define f_nround(bo, bi, k) \ - f_rn(bo, bi, 0, k); \ - f_rn(bo, bi, 1, k); \ - f_rn(bo, bi, 2, k); \ - f_rn(bo, bi, 3, k); \ - k += 4 - -#define f_lround(bo, bi, k) \ - f_rl(bo, bi, 0, k); \ - f_rl(bo, bi, 1, k); \ - f_rl(bo, bi, 2, k); \ - f_rl(bo, bi, 3, k) +#define f_rn(bo, bi, n, k) do { \ + bo[n] = crypto_ft_tab[0][byte(bi[n], 0)] ^ \ + crypto_ft_tab[1][byte(bi[(n + 1) & 3], 1)] ^ \ + crypto_ft_tab[2][byte(bi[(n + 2) & 3], 2)] ^ \ + crypto_ft_tab[3][byte(bi[(n + 3) & 3], 3)] ^ *(k + n); \ +} while (0) + +#define f_nround(bo, bi, k) do {\ + f_rn(bo, bi, 0, k); \ + f_rn(bo, bi, 1, k); \ + f_rn(bo, bi, 2, k); \ + f_rn(bo, bi, 3, k); \ + k += 4; \ +} while (0) + +#define f_rl(bo, bi, n, k) do { \ + bo[n] = crypto_fl_tab[0][byte(bi[n], 0)] ^ \ + crypto_fl_tab[1][byte(bi[(n + 1) & 3], 1)] ^ \ + crypto_fl_tab[2][byte(bi[(n + 2) & 3], 2)] ^ \ + crypto_fl_tab[3][byte(bi[(n + 3) & 3], 3)] ^ *(k + n); \ +} while (0) + +#define f_lround(bo, bi, k) do {\ + f_rl(bo, bi, 0, k); \ + f_rl(bo, bi, 1, k); \ + f_rl(bo, bi, 2, k); \ + f_rl(bo, bi, 3, k); \ +} while (0) static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { - const struct aes_ctx *ctx = crypto_tfm_ctx(tfm); + const struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm); const __le32 *src = (const __le32 *)in; __le32 *dst = (__le32 *)out; u32 b0[4], b1[4]; - const u32 *kp = E_KEY + 4; + const u32 *kp = ctx->key_enc + 4; + const int key_len = ctx->key_length; - b0[0] = le32_to_cpu(src[0]) ^ E_KEY[0]; - b0[1] = le32_to_cpu(src[1]) ^ E_KEY[1]; - b0[2] = le32_to_cpu(src[2]) ^ E_KEY[2]; - b0[3] = le32_to_cpu(src[3]) ^ E_KEY[3]; + b0[0] = le32_to_cpu(src[0]) ^ ctx->key_enc[0]; + b0[1] = le32_to_cpu(src[1]) ^ ctx->key_enc[1]; + b0[2] = le32_to_cpu(src[2]) ^ ctx->key_enc[2]; + b0[3] = le32_to_cpu(src[3]) ^ ctx->key_enc[3]; - if (ctx->key_length > 24) { - f_nround (b1, b0, kp); - f_nround (b0, b1, kp); + if (key_len > 24) { + f_nround(b1, b0, kp); + f_nround(b0, b1, kp); } - if (ctx->key_length > 16) { - f_nround (b1, b0, kp); - f_nround (b0, b1, kp); + if (key_len > 16) { + f_nround(b1, b0, kp); + f_nround(b0, b1, kp); } - f_nround (b1, b0, kp); - f_nround (b0, b1, kp); - f_nround (b1, b0, kp); - f_nround (b0, b1, kp); - f_nround (b1, b0, kp); - f_nround (b0, b1, kp); - f_nround (b1, b0, kp); - f_nround (b0, b1, kp); - f_nround (b1, b0, kp); - f_lround (b0, b1, kp); + f_nround(b1, b0, kp); + f_nround(b0, b1, kp); + f_nround(b1, b0, kp); + f_nround(b0, b1, kp); + f_nround(b1, b0, kp); + f_nround(b0, b1, kp); + f_nround(b1, b0, kp); + f_nround(b0, b1, kp); + f_nround(b1, b0, kp); + f_lround(b0, b1, kp); dst[0] = cpu_to_le32(b0[0]); dst[1] = cpu_to_le32(b0[1]); @@ -361,53 +360,69 @@ static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) /* decrypt a block of text */ -#define i_nround(bo, bi, k) \ - i_rn(bo, bi, 0, k); \ - i_rn(bo, bi, 1, k); \ - i_rn(bo, bi, 2, k); \ - i_rn(bo, bi, 3, k); \ - k -= 4 - -#define i_lround(bo, bi, k) \ - i_rl(bo, bi, 0, k); \ - i_rl(bo, bi, 1, k); \ - i_rl(bo, bi, 2, k); \ - i_rl(bo, bi, 3, k) +#define i_rn(bo, bi, n, k) do { \ + bo[n] = crypto_it_tab[0][byte(bi[n], 0)] ^ \ + crypto_it_tab[1][byte(bi[(n + 3) & 3], 1)] ^ \ + crypto_it_tab[2][byte(bi[(n + 2) & 3], 2)] ^ \ + crypto_it_tab[3][byte(bi[(n + 1) & 3], 3)] ^ *(k + n); \ +} while (0) + +#define i_nround(bo, bi, k) do {\ + i_rn(bo, bi, 0, k); \ + i_rn(bo, bi, 1, k); \ + i_rn(bo, bi, 2, k); \ + i_rn(bo, bi, 3, k); \ + k += 4; \ +} while (0) + +#define i_rl(bo, bi, n, k) do { \ + bo[n] = crypto_il_tab[0][byte(bi[n], 0)] ^ \ + crypto_il_tab[1][byte(bi[(n + 3) & 3], 1)] ^ \ + crypto_il_tab[2][byte(bi[(n + 2) & 3], 2)] ^ \ + crypto_il_tab[3][byte(bi[(n + 1) & 3], 3)] ^ *(k + n); \ +} while (0) + +#define i_lround(bo, bi, k) do {\ + i_rl(bo, bi, 0, k); \ + i_rl(bo, bi, 1, k); \ + i_rl(bo, bi, 2, k); \ + i_rl(bo, bi, 3, k); \ +} while (0) static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { - const struct aes_ctx *ctx = crypto_tfm_ctx(tfm); + const struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm); const __le32 *src = (const __le32 *)in; __le32 *dst = (__le32 *)out; u32 b0[4], b1[4]; const int key_len = ctx->key_length; - const u32 *kp = D_KEY + key_len + 20; + const u32 *kp = ctx->key_dec + 4; - b0[0] = le32_to_cpu(src[0]) ^ E_KEY[key_len + 24]; - b0[1] = le32_to_cpu(src[1]) ^ E_KEY[key_len + 25]; - b0[2] = le32_to_cpu(src[2]) ^ E_KEY[key_len + 26]; - b0[3] = le32_to_cpu(src[3]) ^ E_KEY[key_len + 27]; + b0[0] = le32_to_cpu(src[0]) ^ ctx->key_dec[0]; + b0[1] = le32_to_cpu(src[1]) ^ ctx->key_dec[1]; + b0[2] = le32_to_cpu(src[2]) ^ ctx->key_dec[2]; + b0[3] = le32_to_cpu(src[3]) ^ ctx->key_dec[3]; if (key_len > 24) { - i_nround (b1, b0, kp); - i_nround (b0, b1, kp); + i_nround(b1, b0, kp); + i_nround(b0, b1, kp); } if (key_len > 16) { - i_nround (b1, b0, kp); - i_nround (b0, b1, kp); + i_nround(b1, b0, kp); + i_nround(b0, b1, kp); } - i_nround (b1, b0, kp); - i_nround (b0, b1, kp); - i_nround (b1, b0, kp); - i_nround (b0, b1, kp); - i_nround (b1, b0, kp); - i_nround (b0, b1, kp); - i_nround (b1, b0, kp); - i_nround (b0, b1, kp); - i_nround (b1, b0, kp); - i_lround (b0, b1, kp); + i_nround(b1, b0, kp); + i_nround(b0, b1, kp); + i_nround(b1, b0, kp); + i_nround(b0, b1, kp); + i_nround(b1, b0, kp); + i_nround(b0, b1, kp); + i_nround(b1, b0, kp); + i_nround(b0, b1, kp); + i_nround(b1, b0, kp); + i_lround(b0, b1, kp); dst[0] = cpu_to_le32(b0[0]); dst[1] = cpu_to_le32(b0[1]); @@ -415,14 +430,13 @@ static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) dst[3] = cpu_to_le32(b0[3]); } - static struct crypto_alg aes_alg = { .cra_name = "aes", .cra_driver_name = "aes-generic", .cra_priority = 100, .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct aes_ctx), + .cra_ctxsize = sizeof(struct crypto_aes_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), @@ -430,9 +444,9 @@ static struct crypto_alg aes_alg = { .cipher = { .cia_min_keysize = AES_MIN_KEY_SIZE, .cia_max_keysize = AES_MAX_KEY_SIZE, - .cia_setkey = aes_set_key, - .cia_encrypt = aes_encrypt, - .cia_decrypt = aes_decrypt + .cia_setkey = crypto_aes_set_key, + .cia_encrypt = aes_encrypt, + .cia_decrypt = aes_decrypt } } }; diff --git a/crypto/algapi.c b/crypto/algapi.c index 8383282de1dd..e65cb50cf4af 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -472,7 +472,7 @@ int crypto_check_attr_type(struct rtattr **tb, u32 type) } EXPORT_SYMBOL_GPL(crypto_check_attr_type); -struct crypto_alg *crypto_attr_alg(struct rtattr *rta, u32 type, u32 mask) +const char *crypto_attr_alg_name(struct rtattr *rta) { struct crypto_attr_alg *alga; @@ -486,7 +486,21 @@ struct crypto_alg *crypto_attr_alg(struct rtattr *rta, u32 type, u32 mask) alga = RTA_DATA(rta); alga->name[CRYPTO_MAX_ALG_NAME - 1] = 0; - return crypto_alg_mod_lookup(alga->name, type, mask); + return alga->name; +} +EXPORT_SYMBOL_GPL(crypto_attr_alg_name); + +struct crypto_alg *crypto_attr_alg(struct rtattr *rta, u32 type, u32 mask) +{ + const char *name; + int err; + + name = crypto_attr_alg_name(rta); + err = PTR_ERR(name); + if (IS_ERR(name)) + return ERR_PTR(err); + + return crypto_alg_mod_lookup(name, type, mask); } EXPORT_SYMBOL_GPL(crypto_attr_alg); @@ -605,6 +619,53 @@ int crypto_tfm_in_queue(struct crypto_queue *queue, struct crypto_tfm *tfm) } EXPORT_SYMBOL_GPL(crypto_tfm_in_queue); +static inline void crypto_inc_byte(u8 *a, unsigned int size) +{ + u8 *b = (a + size); + u8 c; + + for (; size; size--) { + c = *--b + 1; + *b = c; + if (c) + break; + } +} + +void crypto_inc(u8 *a, unsigned int size) +{ + __be32 *b = (__be32 *)(a + size); + u32 c; + + for (; size >= 4; size -= 4) { + c = be32_to_cpu(*--b) + 1; + *b = cpu_to_be32(c); + if (c) + return; + } + + crypto_inc_byte(a, size); +} +EXPORT_SYMBOL_GPL(crypto_inc); + +static inline void crypto_xor_byte(u8 *a, const u8 *b, unsigned int size) +{ + for (; size; size--) + *a++ ^= *b++; +} + +void crypto_xor(u8 *dst, const u8 *src, unsigned int size) +{ + u32 *a = (u32 *)dst; + u32 *b = (u32 *)src; + + for (; size >= 4; size -= 4) + *a++ ^= *b++; + + crypto_xor_byte((u8 *)a, (u8 *)b, size); +} +EXPORT_SYMBOL_GPL(crypto_xor); + static int __init crypto_algapi_init(void) { crypto_init_proc(); diff --git a/crypto/api.c b/crypto/api.c index 1f5c72477356..a2496d1bc6d4 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -137,7 +137,7 @@ static struct crypto_alg *crypto_larval_alloc(const char *name, u32 type, return alg; } -static void crypto_larval_kill(struct crypto_alg *alg) +void crypto_larval_kill(struct crypto_alg *alg) { struct crypto_larval *larval = (void *)alg; @@ -147,6 +147,7 @@ static void crypto_larval_kill(struct crypto_alg *alg) complete_all(&larval->completion); crypto_alg_put(alg); } +EXPORT_SYMBOL_GPL(crypto_larval_kill); static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg) { @@ -176,11 +177,9 @@ static struct crypto_alg *crypto_alg_lookup(const char *name, u32 type, return alg; } -struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask) +struct crypto_alg *crypto_larval_lookup(const char *name, u32 type, u32 mask) { struct crypto_alg *alg; - struct crypto_alg *larval; - int ok; if (!name) return ERR_PTR(-ENOENT); @@ -193,7 +192,17 @@ struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask) if (alg) return crypto_is_larval(alg) ? crypto_larval_wait(alg) : alg; - larval = crypto_larval_alloc(name, type, mask); + return crypto_larval_alloc(name, type, mask); +} +EXPORT_SYMBOL_GPL(crypto_larval_lookup); + +struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask) +{ + struct crypto_alg *alg; + struct crypto_alg *larval; + int ok; + + larval = crypto_larval_lookup(name, type, mask); if (IS_ERR(larval) || !crypto_is_larval(larval)) return larval; diff --git a/crypto/authenc.c b/crypto/authenc.c index 126a529b496d..ed8ac5a6fa5f 100644 --- a/crypto/authenc.c +++ b/crypto/authenc.c @@ -10,22 +10,21 @@ * */ -#include <crypto/algapi.h> +#include <crypto/aead.h> +#include <crypto/internal/skcipher.h> +#include <crypto/authenc.h> +#include <crypto/scatterwalk.h> #include <linux/err.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/rtnetlink.h> #include <linux/slab.h> #include <linux/spinlock.h> -#include "scatterwalk.h" - struct authenc_instance_ctx { struct crypto_spawn auth; - struct crypto_spawn enc; - - unsigned int authsize; - unsigned int enckeylen; + struct crypto_skcipher_spawn enc; }; struct crypto_authenc_ctx { @@ -37,19 +36,31 @@ struct crypto_authenc_ctx { static int crypto_authenc_setkey(struct crypto_aead *authenc, const u8 *key, unsigned int keylen) { - struct authenc_instance_ctx *ictx = - crypto_instance_ctx(crypto_aead_alg_instance(authenc)); - unsigned int enckeylen = ictx->enckeylen; unsigned int authkeylen; + unsigned int enckeylen; struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); struct crypto_hash *auth = ctx->auth; struct crypto_ablkcipher *enc = ctx->enc; + struct rtattr *rta = (void *)key; + struct crypto_authenc_key_param *param; int err = -EINVAL; - if (keylen < enckeylen) { - crypto_aead_set_flags(authenc, CRYPTO_TFM_RES_BAD_KEY_LEN); - goto out; - } + if (!RTA_OK(rta, keylen)) + goto badkey; + if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM) + goto badkey; + if (RTA_PAYLOAD(rta) < sizeof(*param)) + goto badkey; + + param = RTA_DATA(rta); + enckeylen = be32_to_cpu(param->enckeylen); + + key += RTA_ALIGN(rta->rta_len); + keylen -= RTA_ALIGN(rta->rta_len); + + if (keylen < enckeylen) + goto badkey; + authkeylen = keylen - enckeylen; crypto_hash_clear_flags(auth, CRYPTO_TFM_REQ_MASK); @@ -71,21 +82,38 @@ static int crypto_authenc_setkey(struct crypto_aead *authenc, const u8 *key, out: return err; + +badkey: + crypto_aead_set_flags(authenc, CRYPTO_TFM_RES_BAD_KEY_LEN); + goto out; } -static int crypto_authenc_hash(struct aead_request *req) +static void authenc_chain(struct scatterlist *head, struct scatterlist *sg, + int chain) +{ + if (chain) { + head->length += sg->length; + sg = scatterwalk_sg_next(sg); + } + + if (sg) + scatterwalk_sg_chain(head, 2, sg); + else + sg_mark_end(head); +} + +static u8 *crypto_authenc_hash(struct aead_request *req, unsigned int flags, + struct scatterlist *cipher, + unsigned int cryptlen) { struct crypto_aead *authenc = crypto_aead_reqtfm(req); - struct authenc_instance_ctx *ictx = - crypto_instance_ctx(crypto_aead_alg_instance(authenc)); struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); struct crypto_hash *auth = ctx->auth; struct hash_desc desc = { .tfm = auth, + .flags = aead_request_flags(req) & flags, }; u8 *hash = aead_request_ctx(req); - struct scatterlist *dst = req->dst; - unsigned int cryptlen = req->cryptlen; int err; hash = (u8 *)ALIGN((unsigned long)hash + crypto_hash_alignmask(auth), @@ -100,7 +128,7 @@ static int crypto_authenc_hash(struct aead_request *req) if (err) goto auth_unlock; - err = crypto_hash_update(&desc, dst, cryptlen); + err = crypto_hash_update(&desc, cipher, cryptlen); if (err) goto auth_unlock; @@ -109,17 +137,53 @@ auth_unlock: spin_unlock_bh(&ctx->auth_lock); if (err) - return err; + return ERR_PTR(err); + + return hash; +} - scatterwalk_map_and_copy(hash, dst, cryptlen, ictx->authsize, 1); +static int crypto_authenc_genicv(struct aead_request *req, u8 *iv, + unsigned int flags) +{ + struct crypto_aead *authenc = crypto_aead_reqtfm(req); + struct scatterlist *dst = req->dst; + struct scatterlist cipher[2]; + struct page *dstp; + unsigned int ivsize = crypto_aead_ivsize(authenc); + unsigned int cryptlen; + u8 *vdst; + u8 *hash; + + dstp = sg_page(dst); + vdst = PageHighMem(dstp) ? NULL : page_address(dstp) + dst->offset; + + sg_init_table(cipher, 2); + sg_set_buf(cipher, iv, ivsize); + authenc_chain(cipher, dst, vdst == iv + ivsize); + + cryptlen = req->cryptlen + ivsize; + hash = crypto_authenc_hash(req, flags, cipher, cryptlen); + if (IS_ERR(hash)) + return PTR_ERR(hash); + + scatterwalk_map_and_copy(hash, cipher, cryptlen, + crypto_aead_authsize(authenc), 1); return 0; } static void crypto_authenc_encrypt_done(struct crypto_async_request *req, int err) { - if (!err) - err = crypto_authenc_hash(req->data); + if (!err) { + struct aead_request *areq = req->data; + struct crypto_aead *authenc = crypto_aead_reqtfm(areq); + struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); + struct ablkcipher_request *abreq = aead_request_ctx(areq); + u8 *iv = (u8 *)(abreq + 1) + + crypto_ablkcipher_reqsize(ctx->enc); + + err = crypto_authenc_genicv(areq, iv, 0); + } aead_request_complete(req->data, err); } @@ -129,72 +193,99 @@ static int crypto_authenc_encrypt(struct aead_request *req) struct crypto_aead *authenc = crypto_aead_reqtfm(req); struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); struct ablkcipher_request *abreq = aead_request_ctx(req); + struct crypto_ablkcipher *enc = ctx->enc; + struct scatterlist *dst = req->dst; + unsigned int cryptlen = req->cryptlen; + u8 *iv = (u8 *)(abreq + 1) + crypto_ablkcipher_reqsize(enc); int err; - ablkcipher_request_set_tfm(abreq, ctx->enc); + ablkcipher_request_set_tfm(abreq, enc); ablkcipher_request_set_callback(abreq, aead_request_flags(req), crypto_authenc_encrypt_done, req); - ablkcipher_request_set_crypt(abreq, req->src, req->dst, req->cryptlen, - req->iv); + ablkcipher_request_set_crypt(abreq, req->src, dst, cryptlen, req->iv); + + memcpy(iv, req->iv, crypto_aead_ivsize(authenc)); err = crypto_ablkcipher_encrypt(abreq); if (err) return err; - return crypto_authenc_hash(req); + return crypto_authenc_genicv(req, iv, CRYPTO_TFM_REQ_MAY_SLEEP); } -static int crypto_authenc_verify(struct aead_request *req) +static void crypto_authenc_givencrypt_done(struct crypto_async_request *req, + int err) { - struct crypto_aead *authenc = crypto_aead_reqtfm(req); - struct authenc_instance_ctx *ictx = - crypto_instance_ctx(crypto_aead_alg_instance(authenc)); + if (!err) { + struct aead_givcrypt_request *greq = req->data; + + err = crypto_authenc_genicv(&greq->areq, greq->giv, 0); + } + + aead_request_complete(req->data, err); +} + +static int crypto_authenc_givencrypt(struct aead_givcrypt_request *req) +{ + struct crypto_aead *authenc = aead_givcrypt_reqtfm(req); struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); - struct crypto_hash *auth = ctx->auth; - struct hash_desc desc = { - .tfm = auth, - .flags = aead_request_flags(req), - }; - u8 *ohash = aead_request_ctx(req); - u8 *ihash; - struct scatterlist *src = req->src; - unsigned int cryptlen = req->cryptlen; - unsigned int authsize; + struct aead_request *areq = &req->areq; + struct skcipher_givcrypt_request *greq = aead_request_ctx(areq); + u8 *iv = req->giv; int err; - ohash = (u8 *)ALIGN((unsigned long)ohash + crypto_hash_alignmask(auth), - crypto_hash_alignmask(auth) + 1); - ihash = ohash + crypto_hash_digestsize(auth); - - spin_lock_bh(&ctx->auth_lock); - err = crypto_hash_init(&desc); - if (err) - goto auth_unlock; + skcipher_givcrypt_set_tfm(greq, ctx->enc); + skcipher_givcrypt_set_callback(greq, aead_request_flags(areq), + crypto_authenc_givencrypt_done, areq); + skcipher_givcrypt_set_crypt(greq, areq->src, areq->dst, areq->cryptlen, + areq->iv); + skcipher_givcrypt_set_giv(greq, iv, req->seq); - err = crypto_hash_update(&desc, req->assoc, req->assoclen); + err = crypto_skcipher_givencrypt(greq); if (err) - goto auth_unlock; + return err; - err = crypto_hash_update(&desc, src, cryptlen); - if (err) - goto auth_unlock; + return crypto_authenc_genicv(areq, iv, CRYPTO_TFM_REQ_MAY_SLEEP); +} - err = crypto_hash_final(&desc, ohash); -auth_unlock: - spin_unlock_bh(&ctx->auth_lock); +static int crypto_authenc_verify(struct aead_request *req, + struct scatterlist *cipher, + unsigned int cryptlen) +{ + struct crypto_aead *authenc = crypto_aead_reqtfm(req); + u8 *ohash; + u8 *ihash; + unsigned int authsize; - if (err) - return err; + ohash = crypto_authenc_hash(req, CRYPTO_TFM_REQ_MAY_SLEEP, cipher, + cryptlen); + if (IS_ERR(ohash)) + return PTR_ERR(ohash); - authsize = ictx->authsize; - scatterwalk_map_and_copy(ihash, src, cryptlen, authsize, 0); - return memcmp(ihash, ohash, authsize) ? -EINVAL : 0; + authsize = crypto_aead_authsize(authenc); + ihash = ohash + authsize; + scatterwalk_map_and_copy(ihash, cipher, cryptlen, authsize, 0); + return memcmp(ihash, ohash, authsize) ? -EBADMSG: 0; } -static void crypto_authenc_decrypt_done(struct crypto_async_request *req, - int err) +static int crypto_authenc_iverify(struct aead_request *req, u8 *iv, + unsigned int cryptlen) { - aead_request_complete(req->data, err); + struct crypto_aead *authenc = crypto_aead_reqtfm(req); + struct scatterlist *src = req->src; + struct scatterlist cipher[2]; + struct page *srcp; + unsigned int ivsize = crypto_aead_ivsize(authenc); + u8 *vsrc; + + srcp = sg_page(src); + vsrc = PageHighMem(srcp) ? NULL : page_address(srcp) + src->offset; + + sg_init_table(cipher, 2); + sg_set_buf(cipher, iv, ivsize); + authenc_chain(cipher, src, vsrc == iv + ivsize); + + return crypto_authenc_verify(req, cipher, cryptlen + ivsize); } static int crypto_authenc_decrypt(struct aead_request *req) @@ -202,17 +293,23 @@ static int crypto_authenc_decrypt(struct aead_request *req) struct crypto_aead *authenc = crypto_aead_reqtfm(req); struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); struct ablkcipher_request *abreq = aead_request_ctx(req); + unsigned int cryptlen = req->cryptlen; + unsigned int authsize = crypto_aead_authsize(authenc); + u8 *iv = req->iv; int err; - err = crypto_authenc_verify(req); + if (cryptlen < authsize) + return -EINVAL; + cryptlen -= authsize; + + err = crypto_authenc_iverify(req, iv, cryptlen); if (err) return err; ablkcipher_request_set_tfm(abreq, ctx->enc); ablkcipher_request_set_callback(abreq, aead_request_flags(req), - crypto_authenc_decrypt_done, req); - ablkcipher_request_set_crypt(abreq, req->src, req->dst, req->cryptlen, - req->iv); + req->base.complete, req->base.data); + ablkcipher_request_set_crypt(abreq, req->src, req->dst, cryptlen, iv); return crypto_ablkcipher_decrypt(abreq); } @@ -224,19 +321,13 @@ static int crypto_authenc_init_tfm(struct crypto_tfm *tfm) struct crypto_authenc_ctx *ctx = crypto_tfm_ctx(tfm); struct crypto_hash *auth; struct crypto_ablkcipher *enc; - unsigned int digestsize; int err; auth = crypto_spawn_hash(&ictx->auth); if (IS_ERR(auth)) return PTR_ERR(auth); - err = -EINVAL; - digestsize = crypto_hash_digestsize(auth); - if (ictx->authsize > digestsize) - goto err_free_hash; - - enc = crypto_spawn_ablkcipher(&ictx->enc); + enc = crypto_spawn_skcipher(&ictx->enc); err = PTR_ERR(enc); if (IS_ERR(enc)) goto err_free_hash; @@ -246,9 +337,10 @@ static int crypto_authenc_init_tfm(struct crypto_tfm *tfm) tfm->crt_aead.reqsize = max_t(unsigned int, (crypto_hash_alignmask(auth) & ~(crypto_tfm_ctx_alignment() - 1)) + - digestsize * 2, - sizeof(struct ablkcipher_request) + - crypto_ablkcipher_reqsize(enc)); + crypto_hash_digestsize(auth) * 2, + sizeof(struct skcipher_givcrypt_request) + + crypto_ablkcipher_reqsize(enc) + + crypto_ablkcipher_ivsize(enc)); spin_lock_init(&ctx->auth_lock); @@ -269,75 +361,74 @@ static void crypto_authenc_exit_tfm(struct crypto_tfm *tfm) static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb) { + struct crypto_attr_type *algt; struct crypto_instance *inst; struct crypto_alg *auth; struct crypto_alg *enc; struct authenc_instance_ctx *ctx; - unsigned int authsize; - unsigned int enckeylen; + const char *enc_name; int err; - err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AEAD); - if (err) + algt = crypto_get_attr_type(tb); + err = PTR_ERR(algt); + if (IS_ERR(algt)) return ERR_PTR(err); + if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask) + return ERR_PTR(-EINVAL); + auth = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_HASH, CRYPTO_ALG_TYPE_HASH_MASK); if (IS_ERR(auth)) return ERR_PTR(PTR_ERR(auth)); - err = crypto_attr_u32(tb[2], &authsize); - inst = ERR_PTR(err); - if (err) - goto out_put_auth; - - enc = crypto_attr_alg(tb[3], CRYPTO_ALG_TYPE_BLKCIPHER, - CRYPTO_ALG_TYPE_MASK); - inst = ERR_PTR(PTR_ERR(enc)); - if (IS_ERR(enc)) + enc_name = crypto_attr_alg_name(tb[2]); + err = PTR_ERR(enc_name); + if (IS_ERR(enc_name)) goto out_put_auth; - err = crypto_attr_u32(tb[4], &enckeylen); - if (err) - goto out_put_enc; - inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL); err = -ENOMEM; if (!inst) - goto out_put_enc; - - err = -ENAMETOOLONG; - if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, - "authenc(%s,%u,%s,%u)", auth->cra_name, authsize, - enc->cra_name, enckeylen) >= CRYPTO_MAX_ALG_NAME) - goto err_free_inst; - - if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, - "authenc(%s,%u,%s,%u)", auth->cra_driver_name, - authsize, enc->cra_driver_name, enckeylen) >= - CRYPTO_MAX_ALG_NAME) - goto err_free_inst; + goto out_put_auth; ctx = crypto_instance_ctx(inst); - ctx->authsize = authsize; - ctx->enckeylen = enckeylen; err = crypto_init_spawn(&ctx->auth, auth, inst, CRYPTO_ALG_TYPE_MASK); if (err) goto err_free_inst; - err = crypto_init_spawn(&ctx->enc, enc, inst, CRYPTO_ALG_TYPE_MASK); + crypto_set_skcipher_spawn(&ctx->enc, inst); + err = crypto_grab_skcipher(&ctx->enc, enc_name, 0, + crypto_requires_sync(algt->type, + algt->mask)); if (err) goto err_drop_auth; - inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC; + enc = crypto_skcipher_spawn_alg(&ctx->enc); + + err = -ENAMETOOLONG; + if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, + "authenc(%s,%s)", auth->cra_name, enc->cra_name) >= + CRYPTO_MAX_ALG_NAME) + goto err_drop_enc; + + if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, + "authenc(%s,%s)", auth->cra_driver_name, + enc->cra_driver_name) >= CRYPTO_MAX_ALG_NAME) + goto err_drop_enc; + + inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD; + inst->alg.cra_flags |= enc->cra_flags & CRYPTO_ALG_ASYNC; inst->alg.cra_priority = enc->cra_priority * 10 + auth->cra_priority; inst->alg.cra_blocksize = enc->cra_blocksize; - inst->alg.cra_alignmask = max(auth->cra_alignmask, enc->cra_alignmask); + inst->alg.cra_alignmask = auth->cra_alignmask | enc->cra_alignmask; inst->alg.cra_type = &crypto_aead_type; - inst->alg.cra_aead.ivsize = enc->cra_blkcipher.ivsize; - inst->alg.cra_aead.authsize = authsize; + inst->alg.cra_aead.ivsize = enc->cra_ablkcipher.ivsize; + inst->alg.cra_aead.maxauthsize = auth->cra_type == &crypto_hash_type ? + auth->cra_hash.digestsize : + auth->cra_digest.dia_digestsize; inst->alg.cra_ctxsize = sizeof(struct crypto_authenc_ctx); @@ -347,18 +438,19 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb) inst->alg.cra_aead.setkey = crypto_authenc_setkey; inst->alg.cra_aead.encrypt = crypto_authenc_encrypt; inst->alg.cra_aead.decrypt = crypto_authenc_decrypt; + inst->alg.cra_aead.givencrypt = crypto_authenc_givencrypt; out: - crypto_mod_put(enc); -out_put_auth: crypto_mod_put(auth); return inst; +err_drop_enc: + crypto_drop_skcipher(&ctx->enc); err_drop_auth: crypto_drop_spawn(&ctx->auth); err_free_inst: kfree(inst); -out_put_enc: +out_put_auth: inst = ERR_PTR(err); goto out; } @@ -367,7 +459,7 @@ static void crypto_authenc_free(struct crypto_instance *inst) { struct authenc_instance_ctx *ctx = crypto_instance_ctx(inst); - crypto_drop_spawn(&ctx->enc); + crypto_drop_skcipher(&ctx->enc); crypto_drop_spawn(&ctx->auth); kfree(inst); } diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c index f6c67f9d4e5c..4a7e65c4df4d 100644 --- a/crypto/blkcipher.c +++ b/crypto/blkcipher.c @@ -14,7 +14,8 @@ * */ -#include <linux/crypto.h> +#include <crypto/internal/skcipher.h> +#include <crypto/scatterwalk.h> #include <linux/errno.h> #include <linux/hardirq.h> #include <linux/kernel.h> @@ -25,7 +26,6 @@ #include <linux/string.h> #include "internal.h" -#include "scatterwalk.h" enum { BLKCIPHER_WALK_PHYS = 1 << 0, @@ -433,9 +433,8 @@ static unsigned int crypto_blkcipher_ctxsize(struct crypto_alg *alg, u32 type, struct blkcipher_alg *cipher = &alg->cra_blkcipher; unsigned int len = alg->cra_ctxsize; - type ^= CRYPTO_ALG_ASYNC; - mask &= CRYPTO_ALG_ASYNC; - if ((type & mask) && cipher->ivsize) { + if ((mask & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_MASK && + cipher->ivsize) { len = ALIGN(len, (unsigned long)alg->cra_alignmask + 1); len += cipher->ivsize; } @@ -451,6 +450,11 @@ static int crypto_init_blkcipher_ops_async(struct crypto_tfm *tfm) crt->setkey = async_setkey; crt->encrypt = async_encrypt; crt->decrypt = async_decrypt; + if (!alg->ivsize) { + crt->givencrypt = skcipher_null_givencrypt; + crt->givdecrypt = skcipher_null_givdecrypt; + } + crt->base = __crypto_ablkcipher_cast(tfm); crt->ivsize = alg->ivsize; return 0; @@ -482,9 +486,7 @@ static int crypto_init_blkcipher_ops(struct crypto_tfm *tfm, u32 type, u32 mask) if (alg->ivsize > PAGE_SIZE / 8) return -EINVAL; - type ^= CRYPTO_ALG_ASYNC; - mask &= CRYPTO_ALG_ASYNC; - if (type & mask) + if ((mask & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_MASK) return crypto_init_blkcipher_ops_sync(tfm); else return crypto_init_blkcipher_ops_async(tfm); @@ -499,6 +501,8 @@ static void crypto_blkcipher_show(struct seq_file *m, struct crypto_alg *alg) seq_printf(m, "min keysize : %u\n", alg->cra_blkcipher.min_keysize); seq_printf(m, "max keysize : %u\n", alg->cra_blkcipher.max_keysize); seq_printf(m, "ivsize : %u\n", alg->cra_blkcipher.ivsize); + seq_printf(m, "geniv : %s\n", alg->cra_blkcipher.geniv ?: + "<default>"); } const struct crypto_type crypto_blkcipher_type = { @@ -510,5 +514,187 @@ const struct crypto_type crypto_blkcipher_type = { }; EXPORT_SYMBOL_GPL(crypto_blkcipher_type); +static int crypto_grab_nivcipher(struct crypto_skcipher_spawn *spawn, + const char *name, u32 type, u32 mask) +{ + struct crypto_alg *alg; + int err; + + type = crypto_skcipher_type(type); + mask = crypto_skcipher_mask(mask) | CRYPTO_ALG_GENIV; + + alg = crypto_alg_mod_lookup(name, type, mask); + if (IS_ERR(alg)) + return PTR_ERR(alg); + + err = crypto_init_spawn(&spawn->base, alg, spawn->base.inst, mask); + crypto_mod_put(alg); + return err; +} + +struct crypto_instance *skcipher_geniv_alloc(struct crypto_template *tmpl, + struct rtattr **tb, u32 type, + u32 mask) +{ + struct { + int (*setkey)(struct crypto_ablkcipher *tfm, const u8 *key, + unsigned int keylen); + int (*encrypt)(struct ablkcipher_request *req); + int (*decrypt)(struct ablkcipher_request *req); + + unsigned int min_keysize; + unsigned int max_keysize; + unsigned int ivsize; + + const char *geniv; + } balg; + const char *name; + struct crypto_skcipher_spawn *spawn; + struct crypto_attr_type *algt; + struct crypto_instance *inst; + struct crypto_alg *alg; + int err; + + algt = crypto_get_attr_type(tb); + err = PTR_ERR(algt); + if (IS_ERR(algt)) + return ERR_PTR(err); + + if ((algt->type ^ (CRYPTO_ALG_TYPE_GIVCIPHER | CRYPTO_ALG_GENIV)) & + algt->mask) + return ERR_PTR(-EINVAL); + + name = crypto_attr_alg_name(tb[1]); + err = PTR_ERR(name); + if (IS_ERR(name)) + return ERR_PTR(err); + + inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL); + if (!inst) + return ERR_PTR(-ENOMEM); + + spawn = crypto_instance_ctx(inst); + + /* Ignore async algorithms if necessary. */ + mask |= crypto_requires_sync(algt->type, algt->mask); + + crypto_set_skcipher_spawn(spawn, inst); + err = crypto_grab_nivcipher(spawn, name, type, mask); + if (err) + goto err_free_inst; + + alg = crypto_skcipher_spawn_alg(spawn); + + if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) == + CRYPTO_ALG_TYPE_BLKCIPHER) { + balg.ivsize = alg->cra_blkcipher.ivsize; + balg.min_keysize = alg->cra_blkcipher.min_keysize; + balg.max_keysize = alg->cra_blkcipher.max_keysize; + + balg.setkey = async_setkey; + balg.encrypt = async_encrypt; + balg.decrypt = async_decrypt; + + balg.geniv = alg->cra_blkcipher.geniv; + } else { + balg.ivsize = alg->cra_ablkcipher.ivsize; + balg.min_keysize = alg->cra_ablkcipher.min_keysize; + balg.max_keysize = alg->cra_ablkcipher.max_keysize; + + balg.setkey = alg->cra_ablkcipher.setkey; + balg.encrypt = alg->cra_ablkcipher.encrypt; + balg.decrypt = alg->cra_ablkcipher.decrypt; + + balg.geniv = alg->cra_ablkcipher.geniv; + } + + err = -EINVAL; + if (!balg.ivsize) + goto err_drop_alg; + + /* + * This is only true if we're constructing an algorithm with its + * default IV generator. For the default generator we elide the + * template name and double-check the IV generator. + */ + if (algt->mask & CRYPTO_ALG_GENIV) { + if (!balg.geniv) + balg.geniv = crypto_default_geniv(alg); + err = -EAGAIN; + if (strcmp(tmpl->name, balg.geniv)) + goto err_drop_alg; + + memcpy(inst->alg.cra_name, alg->cra_name, CRYPTO_MAX_ALG_NAME); + memcpy(inst->alg.cra_driver_name, alg->cra_driver_name, + CRYPTO_MAX_ALG_NAME); + } else { + err = -ENAMETOOLONG; + if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, + "%s(%s)", tmpl->name, alg->cra_name) >= + CRYPTO_MAX_ALG_NAME) + goto err_drop_alg; + if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, + "%s(%s)", tmpl->name, alg->cra_driver_name) >= + CRYPTO_MAX_ALG_NAME) + goto err_drop_alg; + } + + inst->alg.cra_flags = CRYPTO_ALG_TYPE_GIVCIPHER | CRYPTO_ALG_GENIV; + inst->alg.cra_flags |= alg->cra_flags & CRYPTO_ALG_ASYNC; + inst->alg.cra_priority = alg->cra_priority; + inst->alg.cra_blocksize = alg->cra_blocksize; + inst->alg.cra_alignmask = alg->cra_alignmask; + inst->alg.cra_type = &crypto_givcipher_type; + + inst->alg.cra_ablkcipher.ivsize = balg.ivsize; + inst->alg.cra_ablkcipher.min_keysize = balg.min_keysize; + inst->alg.cra_ablkcipher.max_keysize = balg.max_keysize; + inst->alg.cra_ablkcipher.geniv = balg.geniv; + + inst->alg.cra_ablkcipher.setkey = balg.setkey; + inst->alg.cra_ablkcipher.encrypt = balg.encrypt; + inst->alg.cra_ablkcipher.decrypt = balg.decrypt; + +out: + return inst; + +err_drop_alg: + crypto_drop_skcipher(spawn); +err_free_inst: + kfree(inst); + inst = ERR_PTR(err); + goto out; +} +EXPORT_SYMBOL_GPL(skcipher_geniv_alloc); + +void skcipher_geniv_free(struct crypto_instance *inst) +{ + crypto_drop_skcipher(crypto_instance_ctx(inst)); + kfree(inst); +} +EXPORT_SYMBOL_GPL(skcipher_geniv_free); + +int skcipher_geniv_init(struct crypto_tfm *tfm) +{ + struct crypto_instance *inst = (void *)tfm->__crt_alg; + struct crypto_ablkcipher *cipher; + + cipher = crypto_spawn_skcipher(crypto_instance_ctx(inst)); + if (IS_ERR(cipher)) + return PTR_ERR(cipher); + + tfm->crt_ablkcipher.base = cipher; + tfm->crt_ablkcipher.reqsize += crypto_ablkcipher_reqsize(cipher); + + return 0; +} +EXPORT_SYMBOL_GPL(skcipher_geniv_init); + +void skcipher_geniv_exit(struct crypto_tfm *tfm) +{ + crypto_free_ablkcipher(tfm->crt_ablkcipher.base); +} +EXPORT_SYMBOL_GPL(skcipher_geniv_exit); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Generic block chaining cipher type"); diff --git a/crypto/camellia.c b/crypto/camellia.c index 6877ecfd90bb..493fee7e0a8b 100644 --- a/crypto/camellia.c +++ b/crypto/camellia.c @@ -36,176 +36,6 @@ #include <linux/kernel.h> #include <linux/module.h> - -#define CAMELLIA_MIN_KEY_SIZE 16 -#define CAMELLIA_MAX_KEY_SIZE 32 -#define CAMELLIA_BLOCK_SIZE 16 -#define CAMELLIA_TABLE_BYTE_LEN 272 -#define CAMELLIA_TABLE_WORD_LEN (CAMELLIA_TABLE_BYTE_LEN / 4) - -typedef u32 KEY_TABLE_TYPE[CAMELLIA_TABLE_WORD_LEN]; - - -/* key constants */ - -#define CAMELLIA_SIGMA1L (0xA09E667FL) -#define CAMELLIA_SIGMA1R (0x3BCC908BL) -#define CAMELLIA_SIGMA2L (0xB67AE858L) -#define CAMELLIA_SIGMA2R (0x4CAA73B2L) -#define CAMELLIA_SIGMA3L (0xC6EF372FL) -#define CAMELLIA_SIGMA3R (0xE94F82BEL) -#define CAMELLIA_SIGMA4L (0x54FF53A5L) -#define CAMELLIA_SIGMA4R (0xF1D36F1CL) -#define CAMELLIA_SIGMA5L (0x10E527FAL) -#define CAMELLIA_SIGMA5R (0xDE682D1DL) -#define CAMELLIA_SIGMA6L (0xB05688C2L) -#define CAMELLIA_SIGMA6R (0xB3E6C1FDL) - -struct camellia_ctx { - int key_length; - KEY_TABLE_TYPE key_table; -}; - - -/* - * macros - */ - - -# define GETU32(pt) (((u32)(pt)[0] << 24) \ - ^ ((u32)(pt)[1] << 16) \ - ^ ((u32)(pt)[2] << 8) \ - ^ ((u32)(pt)[3])) - -#define COPY4WORD(dst, src) \ - do { \ - (dst)[0]=(src)[0]; \ - (dst)[1]=(src)[1]; \ - (dst)[2]=(src)[2]; \ - (dst)[3]=(src)[3]; \ - }while(0) - -#define SWAP4WORD(word) \ - do { \ - CAMELLIA_SWAP4((word)[0]); \ - CAMELLIA_SWAP4((word)[1]); \ - CAMELLIA_SWAP4((word)[2]); \ - CAMELLIA_SWAP4((word)[3]); \ - }while(0) - -#define XOR4WORD(a, b)/* a = a ^ b */ \ - do { \ - (a)[0]^=(b)[0]; \ - (a)[1]^=(b)[1]; \ - (a)[2]^=(b)[2]; \ - (a)[3]^=(b)[3]; \ - }while(0) - -#define XOR4WORD2(a, b, c)/* a = b ^ c */ \ - do { \ - (a)[0]=(b)[0]^(c)[0]; \ - (a)[1]=(b)[1]^(c)[1]; \ - (a)[2]=(b)[2]^(c)[2]; \ - (a)[3]=(b)[3]^(c)[3]; \ - }while(0) - -#define CAMELLIA_SUBKEY_L(INDEX) (subkey[(INDEX)*2]) -#define CAMELLIA_SUBKEY_R(INDEX) (subkey[(INDEX)*2 + 1]) - -/* rotation right shift 1byte */ -#define CAMELLIA_RR8(x) (((x) >> 8) + ((x) << 24)) -/* rotation left shift 1bit */ -#define CAMELLIA_RL1(x) (((x) << 1) + ((x) >> 31)) -/* rotation left shift 1byte */ -#define CAMELLIA_RL8(x) (((x) << 8) + ((x) >> 24)) - -#define CAMELLIA_ROLDQ(ll, lr, rl, rr, w0, w1, bits) \ - do { \ - w0 = ll; \ - ll = (ll << bits) + (lr >> (32 - bits)); \ - lr = (lr << bits) + (rl >> (32 - bits)); \ - rl = (rl << bits) + (rr >> (32 - bits)); \ - rr = (rr << bits) + (w0 >> (32 - bits)); \ - } while(0) - -#define CAMELLIA_ROLDQo32(ll, lr, rl, rr, w0, w1, bits) \ - do { \ - w0 = ll; \ - w1 = lr; \ - ll = (lr << (bits - 32)) + (rl >> (64 - bits)); \ - lr = (rl << (bits - 32)) + (rr >> (64 - bits)); \ - rl = (rr << (bits - 32)) + (w0 >> (64 - bits)); \ - rr = (w0 << (bits - 32)) + (w1 >> (64 - bits)); \ - } while(0) - -#define CAMELLIA_SP1110(INDEX) (camellia_sp1110[(INDEX)]) -#define CAMELLIA_SP0222(INDEX) (camellia_sp0222[(INDEX)]) -#define CAMELLIA_SP3033(INDEX) (camellia_sp3033[(INDEX)]) -#define CAMELLIA_SP4404(INDEX) (camellia_sp4404[(INDEX)]) - -#define CAMELLIA_F(xl, xr, kl, kr, yl, yr, il, ir, t0, t1) \ - do { \ - il = xl ^ kl; \ - ir = xr ^ kr; \ - t0 = il >> 16; \ - t1 = ir >> 16; \ - yl = CAMELLIA_SP1110(ir & 0xff) \ - ^ CAMELLIA_SP0222((t1 >> 8) & 0xff) \ - ^ CAMELLIA_SP3033(t1 & 0xff) \ - ^ CAMELLIA_SP4404((ir >> 8) & 0xff); \ - yr = CAMELLIA_SP1110((t0 >> 8) & 0xff) \ - ^ CAMELLIA_SP0222(t0 & 0xff) \ - ^ CAMELLIA_SP3033((il >> 8) & 0xff) \ - ^ CAMELLIA_SP4404(il & 0xff); \ - yl ^= yr; \ - yr = CAMELLIA_RR8(yr); \ - yr ^= yl; \ - } while(0) - - -/* - * for speed up - * - */ -#define CAMELLIA_FLS(ll, lr, rl, rr, kll, klr, krl, krr, t0, t1, t2, t3) \ - do { \ - t0 = kll; \ - t2 = krr; \ - t0 &= ll; \ - t2 |= rr; \ - rl ^= t2; \ - lr ^= CAMELLIA_RL1(t0); \ - t3 = krl; \ - t1 = klr; \ - t3 &= rl; \ - t1 |= lr; \ - ll ^= t1; \ - rr ^= CAMELLIA_RL1(t3); \ - } while(0) - -#define CAMELLIA_ROUNDSM(xl, xr, kl, kr, yl, yr, il, ir, t0, t1) \ - do { \ - ir = CAMELLIA_SP1110(xr & 0xff); \ - il = CAMELLIA_SP1110((xl>>24) & 0xff); \ - ir ^= CAMELLIA_SP0222((xr>>24) & 0xff); \ - il ^= CAMELLIA_SP0222((xl>>16) & 0xff); \ - ir ^= CAMELLIA_SP3033((xr>>16) & 0xff); \ - il ^= CAMELLIA_SP3033((xl>>8) & 0xff); \ - ir ^= CAMELLIA_SP4404((xr>>8) & 0xff); \ - il ^= CAMELLIA_SP4404(xl & 0xff); \ - il ^= kl; \ - ir ^= il ^ kr; \ - yl ^= ir; \ - yr ^= CAMELLIA_RR8(il) ^ ir; \ - } while(0) - -/** - * Stuff related to the Camellia key schedule - */ -#define SUBL(x) subL[(x)] -#define SUBR(x) subR[(x)] - - static const u32 camellia_sp1110[256] = { 0x70707000,0x82828200,0x2c2c2c00,0xececec00, 0xb3b3b300,0x27272700,0xc0c0c000,0xe5e5e500, @@ -475,67 +305,348 @@ static const u32 camellia_sp4404[256] = { }; +#define CAMELLIA_MIN_KEY_SIZE 16 +#define CAMELLIA_MAX_KEY_SIZE 32 +#define CAMELLIA_BLOCK_SIZE 16 +#define CAMELLIA_TABLE_BYTE_LEN 272 + +/* + * NB: L and R below stand for 'left' and 'right' as in written numbers. + * That is, in (xxxL,xxxR) pair xxxL holds most significant digits, + * _not_ least significant ones! + */ + + +/* key constants */ + +#define CAMELLIA_SIGMA1L (0xA09E667FL) +#define CAMELLIA_SIGMA1R (0x3BCC908BL) +#define CAMELLIA_SIGMA2L (0xB67AE858L) +#define CAMELLIA_SIGMA2R (0x4CAA73B2L) +#define CAMELLIA_SIGMA3L (0xC6EF372FL) +#define CAMELLIA_SIGMA3R (0xE94F82BEL) +#define CAMELLIA_SIGMA4L (0x54FF53A5L) +#define CAMELLIA_SIGMA4R (0xF1D36F1CL) +#define CAMELLIA_SIGMA5L (0x10E527FAL) +#define CAMELLIA_SIGMA5R (0xDE682D1DL) +#define CAMELLIA_SIGMA6L (0xB05688C2L) +#define CAMELLIA_SIGMA6R (0xB3E6C1FDL) + +/* + * macros + */ +#define GETU32(v, pt) \ + do { \ + /* latest breed of gcc is clever enough to use move */ \ + memcpy(&(v), (pt), 4); \ + (v) = be32_to_cpu(v); \ + } while(0) + +/* rotation right shift 1byte */ +#define ROR8(x) (((x) >> 8) + ((x) << 24)) +/* rotation left shift 1bit */ +#define ROL1(x) (((x) << 1) + ((x) >> 31)) +/* rotation left shift 1byte */ +#define ROL8(x) (((x) << 8) + ((x) >> 24)) + +#define ROLDQ(ll, lr, rl, rr, w0, w1, bits) \ + do { \ + w0 = ll; \ + ll = (ll << bits) + (lr >> (32 - bits)); \ + lr = (lr << bits) + (rl >> (32 - bits)); \ + rl = (rl << bits) + (rr >> (32 - bits)); \ + rr = (rr << bits) + (w0 >> (32 - bits)); \ + } while(0) + +#define ROLDQo32(ll, lr, rl, rr, w0, w1, bits) \ + do { \ + w0 = ll; \ + w1 = lr; \ + ll = (lr << (bits - 32)) + (rl >> (64 - bits)); \ + lr = (rl << (bits - 32)) + (rr >> (64 - bits)); \ + rl = (rr << (bits - 32)) + (w0 >> (64 - bits)); \ + rr = (w0 << (bits - 32)) + (w1 >> (64 - bits)); \ + } while(0) + +#define CAMELLIA_F(xl, xr, kl, kr, yl, yr, il, ir, t0, t1) \ + do { \ + il = xl ^ kl; \ + ir = xr ^ kr; \ + t0 = il >> 16; \ + t1 = ir >> 16; \ + yl = camellia_sp1110[(u8)(ir )] \ + ^ camellia_sp0222[ (t1 >> 8)] \ + ^ camellia_sp3033[(u8)(t1 )] \ + ^ camellia_sp4404[(u8)(ir >> 8)]; \ + yr = camellia_sp1110[ (t0 >> 8)] \ + ^ camellia_sp0222[(u8)(t0 )] \ + ^ camellia_sp3033[(u8)(il >> 8)] \ + ^ camellia_sp4404[(u8)(il )]; \ + yl ^= yr; \ + yr = ROR8(yr); \ + yr ^= yl; \ + } while(0) + +#define SUBKEY_L(INDEX) (subkey[(INDEX)*2]) +#define SUBKEY_R(INDEX) (subkey[(INDEX)*2 + 1]) + +static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) +{ + u32 dw, tl, tr; + u32 kw4l, kw4r; + int i; + + /* absorb kw2 to other subkeys */ + /* round 2 */ + subL[3] ^= subL[1]; subR[3] ^= subR[1]; + /* round 4 */ + subL[5] ^= subL[1]; subR[5] ^= subR[1]; + /* round 6 */ + subL[7] ^= subL[1]; subR[7] ^= subR[1]; + subL[1] ^= subR[1] & ~subR[9]; + dw = subL[1] & subL[9], + subR[1] ^= ROL1(dw); /* modified for FLinv(kl2) */ + /* round 8 */ + subL[11] ^= subL[1]; subR[11] ^= subR[1]; + /* round 10 */ + subL[13] ^= subL[1]; subR[13] ^= subR[1]; + /* round 12 */ + subL[15] ^= subL[1]; subR[15] ^= subR[1]; + subL[1] ^= subR[1] & ~subR[17]; + dw = subL[1] & subL[17], + subR[1] ^= ROL1(dw); /* modified for FLinv(kl4) */ + /* round 14 */ + subL[19] ^= subL[1]; subR[19] ^= subR[1]; + /* round 16 */ + subL[21] ^= subL[1]; subR[21] ^= subR[1]; + /* round 18 */ + subL[23] ^= subL[1]; subR[23] ^= subR[1]; + if (max == 24) { + /* kw3 */ + subL[24] ^= subL[1]; subR[24] ^= subR[1]; + + /* absorb kw4 to other subkeys */ + kw4l = subL[25]; kw4r = subR[25]; + } else { + subL[1] ^= subR[1] & ~subR[25]; + dw = subL[1] & subL[25], + subR[1] ^= ROL1(dw); /* modified for FLinv(kl6) */ + /* round 20 */ + subL[27] ^= subL[1]; subR[27] ^= subR[1]; + /* round 22 */ + subL[29] ^= subL[1]; subR[29] ^= subR[1]; + /* round 24 */ + subL[31] ^= subL[1]; subR[31] ^= subR[1]; + /* kw3 */ + subL[32] ^= subL[1]; subR[32] ^= subR[1]; + + /* absorb kw4 to other subkeys */ + kw4l = subL[33]; kw4r = subR[33]; + /* round 23 */ + subL[30] ^= kw4l; subR[30] ^= kw4r; + /* round 21 */ + subL[28] ^= kw4l; subR[28] ^= kw4r; + /* round 19 */ + subL[26] ^= kw4l; subR[26] ^= kw4r; + kw4l ^= kw4r & ~subR[24]; + dw = kw4l & subL[24], + kw4r ^= ROL1(dw); /* modified for FL(kl5) */ + } + /* round 17 */ + subL[22] ^= kw4l; subR[22] ^= kw4r; + /* round 15 */ + subL[20] ^= kw4l; subR[20] ^= kw4r; + /* round 13 */ + subL[18] ^= kw4l; subR[18] ^= kw4r; + kw4l ^= kw4r & ~subR[16]; + dw = kw4l & subL[16], + kw4r ^= ROL1(dw); /* modified for FL(kl3) */ + /* round 11 */ + subL[14] ^= kw4l; subR[14] ^= kw4r; + /* round 9 */ + subL[12] ^= kw4l; subR[12] ^= kw4r; + /* round 7 */ + subL[10] ^= kw4l; subR[10] ^= kw4r; + kw4l ^= kw4r & ~subR[8]; + dw = kw4l & subL[8], + kw4r ^= ROL1(dw); /* modified for FL(kl1) */ + /* round 5 */ + subL[6] ^= kw4l; subR[6] ^= kw4r; + /* round 3 */ + subL[4] ^= kw4l; subR[4] ^= kw4r; + /* round 1 */ + subL[2] ^= kw4l; subR[2] ^= kw4r; + /* kw1 */ + subL[0] ^= kw4l; subR[0] ^= kw4r; + + /* key XOR is end of F-function */ + SUBKEY_L(0) = subL[0] ^ subL[2];/* kw1 */ + SUBKEY_R(0) = subR[0] ^ subR[2]; + SUBKEY_L(2) = subL[3]; /* round 1 */ + SUBKEY_R(2) = subR[3]; + SUBKEY_L(3) = subL[2] ^ subL[4]; /* round 2 */ + SUBKEY_R(3) = subR[2] ^ subR[4]; + SUBKEY_L(4) = subL[3] ^ subL[5]; /* round 3 */ + SUBKEY_R(4) = subR[3] ^ subR[5]; + SUBKEY_L(5) = subL[4] ^ subL[6]; /* round 4 */ + SUBKEY_R(5) = subR[4] ^ subR[6]; + SUBKEY_L(6) = subL[5] ^ subL[7]; /* round 5 */ + SUBKEY_R(6) = subR[5] ^ subR[7]; + tl = subL[10] ^ (subR[10] & ~subR[8]); + dw = tl & subL[8], /* FL(kl1) */ + tr = subR[10] ^ ROL1(dw); + SUBKEY_L(7) = subL[6] ^ tl; /* round 6 */ + SUBKEY_R(7) = subR[6] ^ tr; + SUBKEY_L(8) = subL[8]; /* FL(kl1) */ + SUBKEY_R(8) = subR[8]; + SUBKEY_L(9) = subL[9]; /* FLinv(kl2) */ + SUBKEY_R(9) = subR[9]; + tl = subL[7] ^ (subR[7] & ~subR[9]); + dw = tl & subL[9], /* FLinv(kl2) */ + tr = subR[7] ^ ROL1(dw); + SUBKEY_L(10) = tl ^ subL[11]; /* round 7 */ + SUBKEY_R(10) = tr ^ subR[11]; + SUBKEY_L(11) = subL[10] ^ subL[12]; /* round 8 */ + SUBKEY_R(11) = subR[10] ^ subR[12]; + SUBKEY_L(12) = subL[11] ^ subL[13]; /* round 9 */ + SUBKEY_R(12) = subR[11] ^ subR[13]; + SUBKEY_L(13) = subL[12] ^ subL[14]; /* round 10 */ + SUBKEY_R(13) = subR[12] ^ subR[14]; + SUBKEY_L(14) = subL[13] ^ subL[15]; /* round 11 */ + SUBKEY_R(14) = subR[13] ^ subR[15]; + tl = subL[18] ^ (subR[18] & ~subR[16]); + dw = tl & subL[16], /* FL(kl3) */ + tr = subR[18] ^ ROL1(dw); + SUBKEY_L(15) = subL[14] ^ tl; /* round 12 */ + SUBKEY_R(15) = subR[14] ^ tr; + SUBKEY_L(16) = subL[16]; /* FL(kl3) */ + SUBKEY_R(16) = subR[16]; + SUBKEY_L(17) = subL[17]; /* FLinv(kl4) */ + SUBKEY_R(17) = subR[17]; + tl = subL[15] ^ (subR[15] & ~subR[17]); + dw = tl & subL[17], /* FLinv(kl4) */ + tr = subR[15] ^ ROL1(dw); + SUBKEY_L(18) = tl ^ subL[19]; /* round 13 */ + SUBKEY_R(18) = tr ^ subR[19]; + SUBKEY_L(19) = subL[18] ^ subL[20]; /* round 14 */ + SUBKEY_R(19) = subR[18] ^ subR[20]; + SUBKEY_L(20) = subL[19] ^ subL[21]; /* round 15 */ + SUBKEY_R(20) = subR[19] ^ subR[21]; + SUBKEY_L(21) = subL[20] ^ subL[22]; /* round 16 */ + SUBKEY_R(21) = subR[20] ^ subR[22]; + SUBKEY_L(22) = subL[21] ^ subL[23]; /* round 17 */ + SUBKEY_R(22) = subR[21] ^ subR[23]; + if (max == 24) { + SUBKEY_L(23) = subL[22]; /* round 18 */ + SUBKEY_R(23) = subR[22]; + SUBKEY_L(24) = subL[24] ^ subL[23]; /* kw3 */ + SUBKEY_R(24) = subR[24] ^ subR[23]; + } else { + tl = subL[26] ^ (subR[26] & ~subR[24]); + dw = tl & subL[24], /* FL(kl5) */ + tr = subR[26] ^ ROL1(dw); + SUBKEY_L(23) = subL[22] ^ tl; /* round 18 */ + SUBKEY_R(23) = subR[22] ^ tr; + SUBKEY_L(24) = subL[24]; /* FL(kl5) */ + SUBKEY_R(24) = subR[24]; + SUBKEY_L(25) = subL[25]; /* FLinv(kl6) */ + SUBKEY_R(25) = subR[25]; + tl = subL[23] ^ (subR[23] & ~subR[25]); + dw = tl & subL[25], /* FLinv(kl6) */ + tr = subR[23] ^ ROL1(dw); + SUBKEY_L(26) = tl ^ subL[27]; /* round 19 */ + SUBKEY_R(26) = tr ^ subR[27]; + SUBKEY_L(27) = subL[26] ^ subL[28]; /* round 20 */ + SUBKEY_R(27) = subR[26] ^ subR[28]; + SUBKEY_L(28) = subL[27] ^ subL[29]; /* round 21 */ + SUBKEY_R(28) = subR[27] ^ subR[29]; + SUBKEY_L(29) = subL[28] ^ subL[30]; /* round 22 */ + SUBKEY_R(29) = subR[28] ^ subR[30]; + SUBKEY_L(30) = subL[29] ^ subL[31]; /* round 23 */ + SUBKEY_R(30) = subR[29] ^ subR[31]; + SUBKEY_L(31) = subL[30]; /* round 24 */ + SUBKEY_R(31) = subR[30]; + SUBKEY_L(32) = subL[32] ^ subL[31]; /* kw3 */ + SUBKEY_R(32) = subR[32] ^ subR[31]; + } + + /* apply the inverse of the last half of P-function */ + i = 2; + do { + dw = SUBKEY_L(i + 0) ^ SUBKEY_R(i + 0); dw = ROL8(dw);/* round 1 */ + SUBKEY_R(i + 0) = SUBKEY_L(i + 0) ^ dw; SUBKEY_L(i + 0) = dw; + dw = SUBKEY_L(i + 1) ^ SUBKEY_R(i + 1); dw = ROL8(dw);/* round 2 */ + SUBKEY_R(i + 1) = SUBKEY_L(i + 1) ^ dw; SUBKEY_L(i + 1) = dw; + dw = SUBKEY_L(i + 2) ^ SUBKEY_R(i + 2); dw = ROL8(dw);/* round 3 */ + SUBKEY_R(i + 2) = SUBKEY_L(i + 2) ^ dw; SUBKEY_L(i + 2) = dw; + dw = SUBKEY_L(i + 3) ^ SUBKEY_R(i + 3); dw = ROL8(dw);/* round 4 */ + SUBKEY_R(i + 3) = SUBKEY_L(i + 3) ^ dw; SUBKEY_L(i + 3) = dw; + dw = SUBKEY_L(i + 4) ^ SUBKEY_R(i + 4); dw = ROL8(dw);/* round 5 */ + SUBKEY_R(i + 4) = SUBKEY_L(i + 4) ^ dw; SUBKEY_L(i + 4) = dw; + dw = SUBKEY_L(i + 5) ^ SUBKEY_R(i + 5); dw = ROL8(dw);/* round 6 */ + SUBKEY_R(i + 5) = SUBKEY_L(i + 5) ^ dw; SUBKEY_L(i + 5) = dw; + i += 8; + } while (i < max); +} static void camellia_setup128(const unsigned char *key, u32 *subkey) { u32 kll, klr, krl, krr; u32 il, ir, t0, t1, w0, w1; - u32 kw4l, kw4r, dw, tl, tr; u32 subL[26]; u32 subR[26]; /** - * k == kll || klr || krl || krr (|| is concatination) - */ - kll = GETU32(key ); - klr = GETU32(key + 4); - krl = GETU32(key + 8); - krr = GETU32(key + 12); - /** - * generate KL dependent subkeys + * k == kll || klr || krl || krr (|| is concatenation) */ + GETU32(kll, key ); + GETU32(klr, key + 4); + GETU32(krl, key + 8); + GETU32(krr, key + 12); + + /* generate KL dependent subkeys */ /* kw1 */ - SUBL(0) = kll; SUBR(0) = klr; + subL[0] = kll; subR[0] = klr; /* kw2 */ - SUBL(1) = krl; SUBR(1) = krr; + subL[1] = krl; subR[1] = krr; /* rotation left shift 15bit */ - CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + ROLDQ(kll, klr, krl, krr, w0, w1, 15); /* k3 */ - SUBL(4) = kll; SUBR(4) = klr; + subL[4] = kll; subR[4] = klr; /* k4 */ - SUBL(5) = krl; SUBR(5) = krr; + subL[5] = krl; subR[5] = krr; /* rotation left shift 15+30bit */ - CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 30); + ROLDQ(kll, klr, krl, krr, w0, w1, 30); /* k7 */ - SUBL(10) = kll; SUBR(10) = klr; + subL[10] = kll; subR[10] = klr; /* k8 */ - SUBL(11) = krl; SUBR(11) = krr; + subL[11] = krl; subR[11] = krr; /* rotation left shift 15+30+15bit */ - CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + ROLDQ(kll, klr, krl, krr, w0, w1, 15); /* k10 */ - SUBL(13) = krl; SUBR(13) = krr; + subL[13] = krl; subR[13] = krr; /* rotation left shift 15+30+15+17 bit */ - CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17); + ROLDQ(kll, klr, krl, krr, w0, w1, 17); /* kl3 */ - SUBL(16) = kll; SUBR(16) = klr; + subL[16] = kll; subR[16] = klr; /* kl4 */ - SUBL(17) = krl; SUBR(17) = krr; + subL[17] = krl; subR[17] = krr; /* rotation left shift 15+30+15+17+17 bit */ - CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17); + ROLDQ(kll, klr, krl, krr, w0, w1, 17); /* k13 */ - SUBL(18) = kll; SUBR(18) = klr; + subL[18] = kll; subR[18] = klr; /* k14 */ - SUBL(19) = krl; SUBR(19) = krr; + subL[19] = krl; subR[19] = krr; /* rotation left shift 15+30+15+17+17+17 bit */ - CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17); + ROLDQ(kll, klr, krl, krr, w0, w1, 17); /* k17 */ - SUBL(22) = kll; SUBR(22) = klr; + subL[22] = kll; subR[22] = klr; /* k18 */ - SUBL(23) = krl; SUBR(23) = krr; + subL[23] = krl; subR[23] = krr; /* generate KA */ - kll = SUBL(0); klr = SUBR(0); - krl = SUBL(1); krr = SUBR(1); + kll = subL[0]; klr = subR[0]; + krl = subL[1]; krr = subR[1]; CAMELLIA_F(kll, klr, CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R, w0, w1, il, ir, t0, t1); @@ -555,306 +666,108 @@ static void camellia_setup128(const unsigned char *key, u32 *subkey) /* generate KA dependent subkeys */ /* k1, k2 */ - SUBL(2) = kll; SUBR(2) = klr; - SUBL(3) = krl; SUBR(3) = krr; - CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + subL[2] = kll; subR[2] = klr; + subL[3] = krl; subR[3] = krr; + ROLDQ(kll, klr, krl, krr, w0, w1, 15); /* k5,k6 */ - SUBL(6) = kll; SUBR(6) = klr; - SUBL(7) = krl; SUBR(7) = krr; - CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + subL[6] = kll; subR[6] = klr; + subL[7] = krl; subR[7] = krr; + ROLDQ(kll, klr, krl, krr, w0, w1, 15); /* kl1, kl2 */ - SUBL(8) = kll; SUBR(8) = klr; - SUBL(9) = krl; SUBR(9) = krr; - CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + subL[8] = kll; subR[8] = klr; + subL[9] = krl; subR[9] = krr; + ROLDQ(kll, klr, krl, krr, w0, w1, 15); /* k9 */ - SUBL(12) = kll; SUBR(12) = klr; - CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + subL[12] = kll; subR[12] = klr; + ROLDQ(kll, klr, krl, krr, w0, w1, 15); /* k11, k12 */ - SUBL(14) = kll; SUBR(14) = klr; - SUBL(15) = krl; SUBR(15) = krr; - CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 34); + subL[14] = kll; subR[14] = klr; + subL[15] = krl; subR[15] = krr; + ROLDQo32(kll, klr, krl, krr, w0, w1, 34); /* k15, k16 */ - SUBL(20) = kll; SUBR(20) = klr; - SUBL(21) = krl; SUBR(21) = krr; - CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17); + subL[20] = kll; subR[20] = klr; + subL[21] = krl; subR[21] = krr; + ROLDQ(kll, klr, krl, krr, w0, w1, 17); /* kw3, kw4 */ - SUBL(24) = kll; SUBR(24) = klr; - SUBL(25) = krl; SUBR(25) = krr; + subL[24] = kll; subR[24] = klr; + subL[25] = krl; subR[25] = krr; - - /* absorb kw2 to other subkeys */ - /* round 2 */ - SUBL(3) ^= SUBL(1); SUBR(3) ^= SUBR(1); - /* round 4 */ - SUBL(5) ^= SUBL(1); SUBR(5) ^= SUBR(1); - /* round 6 */ - SUBL(7) ^= SUBL(1); SUBR(7) ^= SUBR(1); - SUBL(1) ^= SUBR(1) & ~SUBR(9); - dw = SUBL(1) & SUBL(9), - SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl2) */ - /* round 8 */ - SUBL(11) ^= SUBL(1); SUBR(11) ^= SUBR(1); - /* round 10 */ - SUBL(13) ^= SUBL(1); SUBR(13) ^= SUBR(1); - /* round 12 */ - SUBL(15) ^= SUBL(1); SUBR(15) ^= SUBR(1); - SUBL(1) ^= SUBR(1) & ~SUBR(17); - dw = SUBL(1) & SUBL(17), - SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl4) */ - /* round 14 */ - SUBL(19) ^= SUBL(1); SUBR(19) ^= SUBR(1); - /* round 16 */ - SUBL(21) ^= SUBL(1); SUBR(21) ^= SUBR(1); - /* round 18 */ - SUBL(23) ^= SUBL(1); SUBR(23) ^= SUBR(1); - /* kw3 */ - SUBL(24) ^= SUBL(1); SUBR(24) ^= SUBR(1); - - /* absorb kw4 to other subkeys */ - kw4l = SUBL(25); kw4r = SUBR(25); - /* round 17 */ - SUBL(22) ^= kw4l; SUBR(22) ^= kw4r; - /* round 15 */ - SUBL(20) ^= kw4l; SUBR(20) ^= kw4r; - /* round 13 */ - SUBL(18) ^= kw4l; SUBR(18) ^= kw4r; - kw4l ^= kw4r & ~SUBR(16); - dw = kw4l & SUBL(16), - kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl3) */ - /* round 11 */ - SUBL(14) ^= kw4l; SUBR(14) ^= kw4r; - /* round 9 */ - SUBL(12) ^= kw4l; SUBR(12) ^= kw4r; - /* round 7 */ - SUBL(10) ^= kw4l; SUBR(10) ^= kw4r; - kw4l ^= kw4r & ~SUBR(8); - dw = kw4l & SUBL(8), - kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl1) */ - /* round 5 */ - SUBL(6) ^= kw4l; SUBR(6) ^= kw4r; - /* round 3 */ - SUBL(4) ^= kw4l; SUBR(4) ^= kw4r; - /* round 1 */ - SUBL(2) ^= kw4l; SUBR(2) ^= kw4r; - /* kw1 */ - SUBL(0) ^= kw4l; SUBR(0) ^= kw4r; - - - /* key XOR is end of F-function */ - CAMELLIA_SUBKEY_L(0) = SUBL(0) ^ SUBL(2);/* kw1 */ - CAMELLIA_SUBKEY_R(0) = SUBR(0) ^ SUBR(2); - CAMELLIA_SUBKEY_L(2) = SUBL(3); /* round 1 */ - CAMELLIA_SUBKEY_R(2) = SUBR(3); - CAMELLIA_SUBKEY_L(3) = SUBL(2) ^ SUBL(4); /* round 2 */ - CAMELLIA_SUBKEY_R(3) = SUBR(2) ^ SUBR(4); - CAMELLIA_SUBKEY_L(4) = SUBL(3) ^ SUBL(5); /* round 3 */ - CAMELLIA_SUBKEY_R(4) = SUBR(3) ^ SUBR(5); - CAMELLIA_SUBKEY_L(5) = SUBL(4) ^ SUBL(6); /* round 4 */ - CAMELLIA_SUBKEY_R(5) = SUBR(4) ^ SUBR(6); - CAMELLIA_SUBKEY_L(6) = SUBL(5) ^ SUBL(7); /* round 5 */ - CAMELLIA_SUBKEY_R(6) = SUBR(5) ^ SUBR(7); - tl = SUBL(10) ^ (SUBR(10) & ~SUBR(8)); - dw = tl & SUBL(8), /* FL(kl1) */ - tr = SUBR(10) ^ CAMELLIA_RL1(dw); - CAMELLIA_SUBKEY_L(7) = SUBL(6) ^ tl; /* round 6 */ - CAMELLIA_SUBKEY_R(7) = SUBR(6) ^ tr; - CAMELLIA_SUBKEY_L(8) = SUBL(8); /* FL(kl1) */ - CAMELLIA_SUBKEY_R(8) = SUBR(8); - CAMELLIA_SUBKEY_L(9) = SUBL(9); /* FLinv(kl2) */ - CAMELLIA_SUBKEY_R(9) = SUBR(9); - tl = SUBL(7) ^ (SUBR(7) & ~SUBR(9)); - dw = tl & SUBL(9), /* FLinv(kl2) */ - tr = SUBR(7) ^ CAMELLIA_RL1(dw); - CAMELLIA_SUBKEY_L(10) = tl ^ SUBL(11); /* round 7 */ - CAMELLIA_SUBKEY_R(10) = tr ^ SUBR(11); - CAMELLIA_SUBKEY_L(11) = SUBL(10) ^ SUBL(12); /* round 8 */ - CAMELLIA_SUBKEY_R(11) = SUBR(10) ^ SUBR(12); - CAMELLIA_SUBKEY_L(12) = SUBL(11) ^ SUBL(13); /* round 9 */ - CAMELLIA_SUBKEY_R(12) = SUBR(11) ^ SUBR(13); - CAMELLIA_SUBKEY_L(13) = SUBL(12) ^ SUBL(14); /* round 10 */ - CAMELLIA_SUBKEY_R(13) = SUBR(12) ^ SUBR(14); - CAMELLIA_SUBKEY_L(14) = SUBL(13) ^ SUBL(15); /* round 11 */ - CAMELLIA_SUBKEY_R(14) = SUBR(13) ^ SUBR(15); - tl = SUBL(18) ^ (SUBR(18) & ~SUBR(16)); - dw = tl & SUBL(16), /* FL(kl3) */ - tr = SUBR(18) ^ CAMELLIA_RL1(dw); - CAMELLIA_SUBKEY_L(15) = SUBL(14) ^ tl; /* round 12 */ - CAMELLIA_SUBKEY_R(15) = SUBR(14) ^ tr; - CAMELLIA_SUBKEY_L(16) = SUBL(16); /* FL(kl3) */ - CAMELLIA_SUBKEY_R(16) = SUBR(16); - CAMELLIA_SUBKEY_L(17) = SUBL(17); /* FLinv(kl4) */ - CAMELLIA_SUBKEY_R(17) = SUBR(17); - tl = SUBL(15) ^ (SUBR(15) & ~SUBR(17)); - dw = tl & SUBL(17), /* FLinv(kl4) */ - tr = SUBR(15) ^ CAMELLIA_RL1(dw); - CAMELLIA_SUBKEY_L(18) = tl ^ SUBL(19); /* round 13 */ - CAMELLIA_SUBKEY_R(18) = tr ^ SUBR(19); - CAMELLIA_SUBKEY_L(19) = SUBL(18) ^ SUBL(20); /* round 14 */ - CAMELLIA_SUBKEY_R(19) = SUBR(18) ^ SUBR(20); - CAMELLIA_SUBKEY_L(20) = SUBL(19) ^ SUBL(21); /* round 15 */ - CAMELLIA_SUBKEY_R(20) = SUBR(19) ^ SUBR(21); - CAMELLIA_SUBKEY_L(21) = SUBL(20) ^ SUBL(22); /* round 16 */ - CAMELLIA_SUBKEY_R(21) = SUBR(20) ^ SUBR(22); - CAMELLIA_SUBKEY_L(22) = SUBL(21) ^ SUBL(23); /* round 17 */ - CAMELLIA_SUBKEY_R(22) = SUBR(21) ^ SUBR(23); - CAMELLIA_SUBKEY_L(23) = SUBL(22); /* round 18 */ - CAMELLIA_SUBKEY_R(23) = SUBR(22); - CAMELLIA_SUBKEY_L(24) = SUBL(24) ^ SUBL(23); /* kw3 */ - CAMELLIA_SUBKEY_R(24) = SUBR(24) ^ SUBR(23); - - /* apply the inverse of the last half of P-function */ - dw = CAMELLIA_SUBKEY_L(2) ^ CAMELLIA_SUBKEY_R(2), - dw = CAMELLIA_RL8(dw);/* round 1 */ - CAMELLIA_SUBKEY_R(2) = CAMELLIA_SUBKEY_L(2) ^ dw, - CAMELLIA_SUBKEY_L(2) = dw; - dw = CAMELLIA_SUBKEY_L(3) ^ CAMELLIA_SUBKEY_R(3), - dw = CAMELLIA_RL8(dw);/* round 2 */ - CAMELLIA_SUBKEY_R(3) = CAMELLIA_SUBKEY_L(3) ^ dw, - CAMELLIA_SUBKEY_L(3) = dw; - dw = CAMELLIA_SUBKEY_L(4) ^ CAMELLIA_SUBKEY_R(4), - dw = CAMELLIA_RL8(dw);/* round 3 */ - CAMELLIA_SUBKEY_R(4) = CAMELLIA_SUBKEY_L(4) ^ dw, - CAMELLIA_SUBKEY_L(4) = dw; - dw = CAMELLIA_SUBKEY_L(5) ^ CAMELLIA_SUBKEY_R(5), - dw = CAMELLIA_RL8(dw);/* round 4 */ - CAMELLIA_SUBKEY_R(5) = CAMELLIA_SUBKEY_L(5) ^ dw, - CAMELLIA_SUBKEY_L(5) = dw; - dw = CAMELLIA_SUBKEY_L(6) ^ CAMELLIA_SUBKEY_R(6), - dw = CAMELLIA_RL8(dw);/* round 5 */ - CAMELLIA_SUBKEY_R(6) = CAMELLIA_SUBKEY_L(6) ^ dw, - CAMELLIA_SUBKEY_L(6) = dw; - dw = CAMELLIA_SUBKEY_L(7) ^ CAMELLIA_SUBKEY_R(7), - dw = CAMELLIA_RL8(dw);/* round 6 */ - CAMELLIA_SUBKEY_R(7) = CAMELLIA_SUBKEY_L(7) ^ dw, - CAMELLIA_SUBKEY_L(7) = dw; - dw = CAMELLIA_SUBKEY_L(10) ^ CAMELLIA_SUBKEY_R(10), - dw = CAMELLIA_RL8(dw);/* round 7 */ - CAMELLIA_SUBKEY_R(10) = CAMELLIA_SUBKEY_L(10) ^ dw, - CAMELLIA_SUBKEY_L(10) = dw; - dw = CAMELLIA_SUBKEY_L(11) ^ CAMELLIA_SUBKEY_R(11), - dw = CAMELLIA_RL8(dw);/* round 8 */ - CAMELLIA_SUBKEY_R(11) = CAMELLIA_SUBKEY_L(11) ^ dw, - CAMELLIA_SUBKEY_L(11) = dw; - dw = CAMELLIA_SUBKEY_L(12) ^ CAMELLIA_SUBKEY_R(12), - dw = CAMELLIA_RL8(dw);/* round 9 */ - CAMELLIA_SUBKEY_R(12) = CAMELLIA_SUBKEY_L(12) ^ dw, - CAMELLIA_SUBKEY_L(12) = dw; - dw = CAMELLIA_SUBKEY_L(13) ^ CAMELLIA_SUBKEY_R(13), - dw = CAMELLIA_RL8(dw);/* round 10 */ - CAMELLIA_SUBKEY_R(13) = CAMELLIA_SUBKEY_L(13) ^ dw, - CAMELLIA_SUBKEY_L(13) = dw; - dw = CAMELLIA_SUBKEY_L(14) ^ CAMELLIA_SUBKEY_R(14), - dw = CAMELLIA_RL8(dw);/* round 11 */ - CAMELLIA_SUBKEY_R(14) = CAMELLIA_SUBKEY_L(14) ^ dw, - CAMELLIA_SUBKEY_L(14) = dw; - dw = CAMELLIA_SUBKEY_L(15) ^ CAMELLIA_SUBKEY_R(15), - dw = CAMELLIA_RL8(dw);/* round 12 */ - CAMELLIA_SUBKEY_R(15) = CAMELLIA_SUBKEY_L(15) ^ dw, - CAMELLIA_SUBKEY_L(15) = dw; - dw = CAMELLIA_SUBKEY_L(18) ^ CAMELLIA_SUBKEY_R(18), - dw = CAMELLIA_RL8(dw);/* round 13 */ - CAMELLIA_SUBKEY_R(18) = CAMELLIA_SUBKEY_L(18) ^ dw, - CAMELLIA_SUBKEY_L(18) = dw; - dw = CAMELLIA_SUBKEY_L(19) ^ CAMELLIA_SUBKEY_R(19), - dw = CAMELLIA_RL8(dw);/* round 14 */ - CAMELLIA_SUBKEY_R(19) = CAMELLIA_SUBKEY_L(19) ^ dw, - CAMELLIA_SUBKEY_L(19) = dw; - dw = CAMELLIA_SUBKEY_L(20) ^ CAMELLIA_SUBKEY_R(20), - dw = CAMELLIA_RL8(dw);/* round 15 */ - CAMELLIA_SUBKEY_R(20) = CAMELLIA_SUBKEY_L(20) ^ dw, - CAMELLIA_SUBKEY_L(20) = dw; - dw = CAMELLIA_SUBKEY_L(21) ^ CAMELLIA_SUBKEY_R(21), - dw = CAMELLIA_RL8(dw);/* round 16 */ - CAMELLIA_SUBKEY_R(21) = CAMELLIA_SUBKEY_L(21) ^ dw, - CAMELLIA_SUBKEY_L(21) = dw; - dw = CAMELLIA_SUBKEY_L(22) ^ CAMELLIA_SUBKEY_R(22), - dw = CAMELLIA_RL8(dw);/* round 17 */ - CAMELLIA_SUBKEY_R(22) = CAMELLIA_SUBKEY_L(22) ^ dw, - CAMELLIA_SUBKEY_L(22) = dw; - dw = CAMELLIA_SUBKEY_L(23) ^ CAMELLIA_SUBKEY_R(23), - dw = CAMELLIA_RL8(dw);/* round 18 */ - CAMELLIA_SUBKEY_R(23) = CAMELLIA_SUBKEY_L(23) ^ dw, - CAMELLIA_SUBKEY_L(23) = dw; - - return; + camellia_setup_tail(subkey, subL, subR, 24); } - static void camellia_setup256(const unsigned char *key, u32 *subkey) { - u32 kll,klr,krl,krr; /* left half of key */ - u32 krll,krlr,krrl,krrr; /* right half of key */ + u32 kll, klr, krl, krr; /* left half of key */ + u32 krll, krlr, krrl, krrr; /* right half of key */ u32 il, ir, t0, t1, w0, w1; /* temporary variables */ - u32 kw4l, kw4r, dw, tl, tr; u32 subL[34]; u32 subR[34]; /** * key = (kll || klr || krl || krr || krll || krlr || krrl || krrr) - * (|| is concatination) + * (|| is concatenation) */ - - kll = GETU32(key ); - klr = GETU32(key + 4); - krl = GETU32(key + 8); - krr = GETU32(key + 12); - krll = GETU32(key + 16); - krlr = GETU32(key + 20); - krrl = GETU32(key + 24); - krrr = GETU32(key + 28); + GETU32(kll, key ); + GETU32(klr, key + 4); + GETU32(krl, key + 8); + GETU32(krr, key + 12); + GETU32(krll, key + 16); + GETU32(krlr, key + 20); + GETU32(krrl, key + 24); + GETU32(krrr, key + 28); /* generate KL dependent subkeys */ /* kw1 */ - SUBL(0) = kll; SUBR(0) = klr; + subL[0] = kll; subR[0] = klr; /* kw2 */ - SUBL(1) = krl; SUBR(1) = krr; - CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 45); + subL[1] = krl; subR[1] = krr; + ROLDQo32(kll, klr, krl, krr, w0, w1, 45); /* k9 */ - SUBL(12) = kll; SUBR(12) = klr; + subL[12] = kll; subR[12] = klr; /* k10 */ - SUBL(13) = krl; SUBR(13) = krr; - CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + subL[13] = krl; subR[13] = krr; + ROLDQ(kll, klr, krl, krr, w0, w1, 15); /* kl3 */ - SUBL(16) = kll; SUBR(16) = klr; + subL[16] = kll; subR[16] = klr; /* kl4 */ - SUBL(17) = krl; SUBR(17) = krr; - CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17); + subL[17] = krl; subR[17] = krr; + ROLDQ(kll, klr, krl, krr, w0, w1, 17); /* k17 */ - SUBL(22) = kll; SUBR(22) = klr; + subL[22] = kll; subR[22] = klr; /* k18 */ - SUBL(23) = krl; SUBR(23) = krr; - CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 34); + subL[23] = krl; subR[23] = krr; + ROLDQo32(kll, klr, krl, krr, w0, w1, 34); /* k23 */ - SUBL(30) = kll; SUBR(30) = klr; + subL[30] = kll; subR[30] = klr; /* k24 */ - SUBL(31) = krl; SUBR(31) = krr; + subL[31] = krl; subR[31] = krr; /* generate KR dependent subkeys */ - CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 15); + ROLDQ(krll, krlr, krrl, krrr, w0, w1, 15); /* k3 */ - SUBL(4) = krll; SUBR(4) = krlr; + subL[4] = krll; subR[4] = krlr; /* k4 */ - SUBL(5) = krrl; SUBR(5) = krrr; - CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 15); + subL[5] = krrl; subR[5] = krrr; + ROLDQ(krll, krlr, krrl, krrr, w0, w1, 15); /* kl1 */ - SUBL(8) = krll; SUBR(8) = krlr; + subL[8] = krll; subR[8] = krlr; /* kl2 */ - SUBL(9) = krrl; SUBR(9) = krrr; - CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30); + subL[9] = krrl; subR[9] = krrr; + ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30); /* k13 */ - SUBL(18) = krll; SUBR(18) = krlr; + subL[18] = krll; subR[18] = krlr; /* k14 */ - SUBL(19) = krrl; SUBR(19) = krrr; - CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 34); + subL[19] = krrl; subR[19] = krrr; + ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 34); /* k19 */ - SUBL(26) = krll; SUBR(26) = krlr; + subL[26] = krll; subR[26] = krlr; /* k20 */ - SUBL(27) = krrl; SUBR(27) = krrr; - CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 34); + subL[27] = krrl; subR[27] = krrr; + ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 34); /* generate KA */ - kll = SUBL(0) ^ krll; klr = SUBR(0) ^ krlr; - krl = SUBL(1) ^ krrl; krr = SUBR(1) ^ krrr; + kll = subL[0] ^ krll; klr = subR[0] ^ krlr; + krl = subL[1] ^ krrl; krr = subR[1] ^ krrr; CAMELLIA_F(kll, klr, CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R, w0, w1, il, ir, t0, t1); @@ -885,310 +798,50 @@ static void camellia_setup256(const unsigned char *key, u32 *subkey) krll ^= w0; krlr ^= w1; /* generate KA dependent subkeys */ - CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + ROLDQ(kll, klr, krl, krr, w0, w1, 15); /* k5 */ - SUBL(6) = kll; SUBR(6) = klr; + subL[6] = kll; subR[6] = klr; /* k6 */ - SUBL(7) = krl; SUBR(7) = krr; - CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 30); + subL[7] = krl; subR[7] = krr; + ROLDQ(kll, klr, krl, krr, w0, w1, 30); /* k11 */ - SUBL(14) = kll; SUBR(14) = klr; + subL[14] = kll; subR[14] = klr; /* k12 */ - SUBL(15) = krl; SUBR(15) = krr; + subL[15] = krl; subR[15] = krr; /* rotation left shift 32bit */ /* kl5 */ - SUBL(24) = klr; SUBR(24) = krl; + subL[24] = klr; subR[24] = krl; /* kl6 */ - SUBL(25) = krr; SUBR(25) = kll; + subL[25] = krr; subR[25] = kll; /* rotation left shift 49 from k11,k12 -> k21,k22 */ - CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 49); + ROLDQo32(kll, klr, krl, krr, w0, w1, 49); /* k21 */ - SUBL(28) = kll; SUBR(28) = klr; + subL[28] = kll; subR[28] = klr; /* k22 */ - SUBL(29) = krl; SUBR(29) = krr; + subL[29] = krl; subR[29] = krr; /* generate KB dependent subkeys */ /* k1 */ - SUBL(2) = krll; SUBR(2) = krlr; + subL[2] = krll; subR[2] = krlr; /* k2 */ - SUBL(3) = krrl; SUBR(3) = krrr; - CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30); + subL[3] = krrl; subR[3] = krrr; + ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30); /* k7 */ - SUBL(10) = krll; SUBR(10) = krlr; + subL[10] = krll; subR[10] = krlr; /* k8 */ - SUBL(11) = krrl; SUBR(11) = krrr; - CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30); + subL[11] = krrl; subR[11] = krrr; + ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30); /* k15 */ - SUBL(20) = krll; SUBR(20) = krlr; + subL[20] = krll; subR[20] = krlr; /* k16 */ - SUBL(21) = krrl; SUBR(21) = krrr; - CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 51); + subL[21] = krrl; subR[21] = krrr; + ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 51); /* kw3 */ - SUBL(32) = krll; SUBR(32) = krlr; + subL[32] = krll; subR[32] = krlr; /* kw4 */ - SUBL(33) = krrl; SUBR(33) = krrr; - - /* absorb kw2 to other subkeys */ - /* round 2 */ - SUBL(3) ^= SUBL(1); SUBR(3) ^= SUBR(1); - /* round 4 */ - SUBL(5) ^= SUBL(1); SUBR(5) ^= SUBR(1); - /* round 6 */ - SUBL(7) ^= SUBL(1); SUBR(7) ^= SUBR(1); - SUBL(1) ^= SUBR(1) & ~SUBR(9); - dw = SUBL(1) & SUBL(9), - SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl2) */ - /* round 8 */ - SUBL(11) ^= SUBL(1); SUBR(11) ^= SUBR(1); - /* round 10 */ - SUBL(13) ^= SUBL(1); SUBR(13) ^= SUBR(1); - /* round 12 */ - SUBL(15) ^= SUBL(1); SUBR(15) ^= SUBR(1); - SUBL(1) ^= SUBR(1) & ~SUBR(17); - dw = SUBL(1) & SUBL(17), - SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl4) */ - /* round 14 */ - SUBL(19) ^= SUBL(1); SUBR(19) ^= SUBR(1); - /* round 16 */ - SUBL(21) ^= SUBL(1); SUBR(21) ^= SUBR(1); - /* round 18 */ - SUBL(23) ^= SUBL(1); SUBR(23) ^= SUBR(1); - SUBL(1) ^= SUBR(1) & ~SUBR(25); - dw = SUBL(1) & SUBL(25), - SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl6) */ - /* round 20 */ - SUBL(27) ^= SUBL(1); SUBR(27) ^= SUBR(1); - /* round 22 */ - SUBL(29) ^= SUBL(1); SUBR(29) ^= SUBR(1); - /* round 24 */ - SUBL(31) ^= SUBL(1); SUBR(31) ^= SUBR(1); - /* kw3 */ - SUBL(32) ^= SUBL(1); SUBR(32) ^= SUBR(1); - - - /* absorb kw4 to other subkeys */ - kw4l = SUBL(33); kw4r = SUBR(33); - /* round 23 */ - SUBL(30) ^= kw4l; SUBR(30) ^= kw4r; - /* round 21 */ - SUBL(28) ^= kw4l; SUBR(28) ^= kw4r; - /* round 19 */ - SUBL(26) ^= kw4l; SUBR(26) ^= kw4r; - kw4l ^= kw4r & ~SUBR(24); - dw = kw4l & SUBL(24), - kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl5) */ - /* round 17 */ - SUBL(22) ^= kw4l; SUBR(22) ^= kw4r; - /* round 15 */ - SUBL(20) ^= kw4l; SUBR(20) ^= kw4r; - /* round 13 */ - SUBL(18) ^= kw4l; SUBR(18) ^= kw4r; - kw4l ^= kw4r & ~SUBR(16); - dw = kw4l & SUBL(16), - kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl3) */ - /* round 11 */ - SUBL(14) ^= kw4l; SUBR(14) ^= kw4r; - /* round 9 */ - SUBL(12) ^= kw4l; SUBR(12) ^= kw4r; - /* round 7 */ - SUBL(10) ^= kw4l; SUBR(10) ^= kw4r; - kw4l ^= kw4r & ~SUBR(8); - dw = kw4l & SUBL(8), - kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl1) */ - /* round 5 */ - SUBL(6) ^= kw4l; SUBR(6) ^= kw4r; - /* round 3 */ - SUBL(4) ^= kw4l; SUBR(4) ^= kw4r; - /* round 1 */ - SUBL(2) ^= kw4l; SUBR(2) ^= kw4r; - /* kw1 */ - SUBL(0) ^= kw4l; SUBR(0) ^= kw4r; + subL[33] = krrl; subR[33] = krrr; - /* key XOR is end of F-function */ - CAMELLIA_SUBKEY_L(0) = SUBL(0) ^ SUBL(2);/* kw1 */ - CAMELLIA_SUBKEY_R(0) = SUBR(0) ^ SUBR(2); - CAMELLIA_SUBKEY_L(2) = SUBL(3); /* round 1 */ - CAMELLIA_SUBKEY_R(2) = SUBR(3); - CAMELLIA_SUBKEY_L(3) = SUBL(2) ^ SUBL(4); /* round 2 */ - CAMELLIA_SUBKEY_R(3) = SUBR(2) ^ SUBR(4); - CAMELLIA_SUBKEY_L(4) = SUBL(3) ^ SUBL(5); /* round 3 */ - CAMELLIA_SUBKEY_R(4) = SUBR(3) ^ SUBR(5); - CAMELLIA_SUBKEY_L(5) = SUBL(4) ^ SUBL(6); /* round 4 */ - CAMELLIA_SUBKEY_R(5) = SUBR(4) ^ SUBR(6); - CAMELLIA_SUBKEY_L(6) = SUBL(5) ^ SUBL(7); /* round 5 */ - CAMELLIA_SUBKEY_R(6) = SUBR(5) ^ SUBR(7); - tl = SUBL(10) ^ (SUBR(10) & ~SUBR(8)); - dw = tl & SUBL(8), /* FL(kl1) */ - tr = SUBR(10) ^ CAMELLIA_RL1(dw); - CAMELLIA_SUBKEY_L(7) = SUBL(6) ^ tl; /* round 6 */ - CAMELLIA_SUBKEY_R(7) = SUBR(6) ^ tr; - CAMELLIA_SUBKEY_L(8) = SUBL(8); /* FL(kl1) */ - CAMELLIA_SUBKEY_R(8) = SUBR(8); - CAMELLIA_SUBKEY_L(9) = SUBL(9); /* FLinv(kl2) */ - CAMELLIA_SUBKEY_R(9) = SUBR(9); - tl = SUBL(7) ^ (SUBR(7) & ~SUBR(9)); - dw = tl & SUBL(9), /* FLinv(kl2) */ - tr = SUBR(7) ^ CAMELLIA_RL1(dw); - CAMELLIA_SUBKEY_L(10) = tl ^ SUBL(11); /* round 7 */ - CAMELLIA_SUBKEY_R(10) = tr ^ SUBR(11); - CAMELLIA_SUBKEY_L(11) = SUBL(10) ^ SUBL(12); /* round 8 */ - CAMELLIA_SUBKEY_R(11) = SUBR(10) ^ SUBR(12); - CAMELLIA_SUBKEY_L(12) = SUBL(11) ^ SUBL(13); /* round 9 */ - CAMELLIA_SUBKEY_R(12) = SUBR(11) ^ SUBR(13); - CAMELLIA_SUBKEY_L(13) = SUBL(12) ^ SUBL(14); /* round 10 */ - CAMELLIA_SUBKEY_R(13) = SUBR(12) ^ SUBR(14); - CAMELLIA_SUBKEY_L(14) = SUBL(13) ^ SUBL(15); /* round 11 */ - CAMELLIA_SUBKEY_R(14) = SUBR(13) ^ SUBR(15); - tl = SUBL(18) ^ (SUBR(18) & ~SUBR(16)); - dw = tl & SUBL(16), /* FL(kl3) */ - tr = SUBR(18) ^ CAMELLIA_RL1(dw); - CAMELLIA_SUBKEY_L(15) = SUBL(14) ^ tl; /* round 12 */ - CAMELLIA_SUBKEY_R(15) = SUBR(14) ^ tr; - CAMELLIA_SUBKEY_L(16) = SUBL(16); /* FL(kl3) */ - CAMELLIA_SUBKEY_R(16) = SUBR(16); - CAMELLIA_SUBKEY_L(17) = SUBL(17); /* FLinv(kl4) */ - CAMELLIA_SUBKEY_R(17) = SUBR(17); - tl = SUBL(15) ^ (SUBR(15) & ~SUBR(17)); - dw = tl & SUBL(17), /* FLinv(kl4) */ - tr = SUBR(15) ^ CAMELLIA_RL1(dw); - CAMELLIA_SUBKEY_L(18) = tl ^ SUBL(19); /* round 13 */ - CAMELLIA_SUBKEY_R(18) = tr ^ SUBR(19); - CAMELLIA_SUBKEY_L(19) = SUBL(18) ^ SUBL(20); /* round 14 */ - CAMELLIA_SUBKEY_R(19) = SUBR(18) ^ SUBR(20); - CAMELLIA_SUBKEY_L(20) = SUBL(19) ^ SUBL(21); /* round 15 */ - CAMELLIA_SUBKEY_R(20) = SUBR(19) ^ SUBR(21); - CAMELLIA_SUBKEY_L(21) = SUBL(20) ^ SUBL(22); /* round 16 */ - CAMELLIA_SUBKEY_R(21) = SUBR(20) ^ SUBR(22); - CAMELLIA_SUBKEY_L(22) = SUBL(21) ^ SUBL(23); /* round 17 */ - CAMELLIA_SUBKEY_R(22) = SUBR(21) ^ SUBR(23); - tl = SUBL(26) ^ (SUBR(26) - & ~SUBR(24)); - dw = tl & SUBL(24), /* FL(kl5) */ - tr = SUBR(26) ^ CAMELLIA_RL1(dw); - CAMELLIA_SUBKEY_L(23) = SUBL(22) ^ tl; /* round 18 */ - CAMELLIA_SUBKEY_R(23) = SUBR(22) ^ tr; - CAMELLIA_SUBKEY_L(24) = SUBL(24); /* FL(kl5) */ - CAMELLIA_SUBKEY_R(24) = SUBR(24); - CAMELLIA_SUBKEY_L(25) = SUBL(25); /* FLinv(kl6) */ - CAMELLIA_SUBKEY_R(25) = SUBR(25); - tl = SUBL(23) ^ (SUBR(23) & - ~SUBR(25)); - dw = tl & SUBL(25), /* FLinv(kl6) */ - tr = SUBR(23) ^ CAMELLIA_RL1(dw); - CAMELLIA_SUBKEY_L(26) = tl ^ SUBL(27); /* round 19 */ - CAMELLIA_SUBKEY_R(26) = tr ^ SUBR(27); - CAMELLIA_SUBKEY_L(27) = SUBL(26) ^ SUBL(28); /* round 20 */ - CAMELLIA_SUBKEY_R(27) = SUBR(26) ^ SUBR(28); - CAMELLIA_SUBKEY_L(28) = SUBL(27) ^ SUBL(29); /* round 21 */ - CAMELLIA_SUBKEY_R(28) = SUBR(27) ^ SUBR(29); - CAMELLIA_SUBKEY_L(29) = SUBL(28) ^ SUBL(30); /* round 22 */ - CAMELLIA_SUBKEY_R(29) = SUBR(28) ^ SUBR(30); - CAMELLIA_SUBKEY_L(30) = SUBL(29) ^ SUBL(31); /* round 23 */ - CAMELLIA_SUBKEY_R(30) = SUBR(29) ^ SUBR(31); - CAMELLIA_SUBKEY_L(31) = SUBL(30); /* round 24 */ - CAMELLIA_SUBKEY_R(31) = SUBR(30); - CAMELLIA_SUBKEY_L(32) = SUBL(32) ^ SUBL(31); /* kw3 */ - CAMELLIA_SUBKEY_R(32) = SUBR(32) ^ SUBR(31); - - /* apply the inverse of the last half of P-function */ - dw = CAMELLIA_SUBKEY_L(2) ^ CAMELLIA_SUBKEY_R(2), - dw = CAMELLIA_RL8(dw);/* round 1 */ - CAMELLIA_SUBKEY_R(2) = CAMELLIA_SUBKEY_L(2) ^ dw, - CAMELLIA_SUBKEY_L(2) = dw; - dw = CAMELLIA_SUBKEY_L(3) ^ CAMELLIA_SUBKEY_R(3), - dw = CAMELLIA_RL8(dw);/* round 2 */ - CAMELLIA_SUBKEY_R(3) = CAMELLIA_SUBKEY_L(3) ^ dw, - CAMELLIA_SUBKEY_L(3) = dw; - dw = CAMELLIA_SUBKEY_L(4) ^ CAMELLIA_SUBKEY_R(4), - dw = CAMELLIA_RL8(dw);/* round 3 */ - CAMELLIA_SUBKEY_R(4) = CAMELLIA_SUBKEY_L(4) ^ dw, - CAMELLIA_SUBKEY_L(4) = dw; - dw = CAMELLIA_SUBKEY_L(5) ^ CAMELLIA_SUBKEY_R(5), - dw = CAMELLIA_RL8(dw);/* round 4 */ - CAMELLIA_SUBKEY_R(5) = CAMELLIA_SUBKEY_L(5) ^ dw, - CAMELLIA_SUBKEY_L(5) = dw; - dw = CAMELLIA_SUBKEY_L(6) ^ CAMELLIA_SUBKEY_R(6), - dw = CAMELLIA_RL8(dw);/* round 5 */ - CAMELLIA_SUBKEY_R(6) = CAMELLIA_SUBKEY_L(6) ^ dw, - CAMELLIA_SUBKEY_L(6) = dw; - dw = CAMELLIA_SUBKEY_L(7) ^ CAMELLIA_SUBKEY_R(7), - dw = CAMELLIA_RL8(dw);/* round 6 */ - CAMELLIA_SUBKEY_R(7) = CAMELLIA_SUBKEY_L(7) ^ dw, - CAMELLIA_SUBKEY_L(7) = dw; - dw = CAMELLIA_SUBKEY_L(10) ^ CAMELLIA_SUBKEY_R(10), - dw = CAMELLIA_RL8(dw);/* round 7 */ - CAMELLIA_SUBKEY_R(10) = CAMELLIA_SUBKEY_L(10) ^ dw, - CAMELLIA_SUBKEY_L(10) = dw; - dw = CAMELLIA_SUBKEY_L(11) ^ CAMELLIA_SUBKEY_R(11), - dw = CAMELLIA_RL8(dw);/* round 8 */ - CAMELLIA_SUBKEY_R(11) = CAMELLIA_SUBKEY_L(11) ^ dw, - CAMELLIA_SUBKEY_L(11) = dw; - dw = CAMELLIA_SUBKEY_L(12) ^ CAMELLIA_SUBKEY_R(12), - dw = CAMELLIA_RL8(dw);/* round 9 */ - CAMELLIA_SUBKEY_R(12) = CAMELLIA_SUBKEY_L(12) ^ dw, - CAMELLIA_SUBKEY_L(12) = dw; - dw = CAMELLIA_SUBKEY_L(13) ^ CAMELLIA_SUBKEY_R(13), - dw = CAMELLIA_RL8(dw);/* round 10 */ - CAMELLIA_SUBKEY_R(13) = CAMELLIA_SUBKEY_L(13) ^ dw, - CAMELLIA_SUBKEY_L(13) = dw; - dw = CAMELLIA_SUBKEY_L(14) ^ CAMELLIA_SUBKEY_R(14), - dw = CAMELLIA_RL8(dw);/* round 11 */ - CAMELLIA_SUBKEY_R(14) = CAMELLIA_SUBKEY_L(14) ^ dw, - CAMELLIA_SUBKEY_L(14) = dw; - dw = CAMELLIA_SUBKEY_L(15) ^ CAMELLIA_SUBKEY_R(15), - dw = CAMELLIA_RL8(dw);/* round 12 */ - CAMELLIA_SUBKEY_R(15) = CAMELLIA_SUBKEY_L(15) ^ dw, - CAMELLIA_SUBKEY_L(15) = dw; - dw = CAMELLIA_SUBKEY_L(18) ^ CAMELLIA_SUBKEY_R(18), - dw = CAMELLIA_RL8(dw);/* round 13 */ - CAMELLIA_SUBKEY_R(18) = CAMELLIA_SUBKEY_L(18) ^ dw, - CAMELLIA_SUBKEY_L(18) = dw; - dw = CAMELLIA_SUBKEY_L(19) ^ CAMELLIA_SUBKEY_R(19), - dw = CAMELLIA_RL8(dw);/* round 14 */ - CAMELLIA_SUBKEY_R(19) = CAMELLIA_SUBKEY_L(19) ^ dw, - CAMELLIA_SUBKEY_L(19) = dw; - dw = CAMELLIA_SUBKEY_L(20) ^ CAMELLIA_SUBKEY_R(20), - dw = CAMELLIA_RL8(dw);/* round 15 */ - CAMELLIA_SUBKEY_R(20) = CAMELLIA_SUBKEY_L(20) ^ dw, - CAMELLIA_SUBKEY_L(20) = dw; - dw = CAMELLIA_SUBKEY_L(21) ^ CAMELLIA_SUBKEY_R(21), - dw = CAMELLIA_RL8(dw);/* round 16 */ - CAMELLIA_SUBKEY_R(21) = CAMELLIA_SUBKEY_L(21) ^ dw, - CAMELLIA_SUBKEY_L(21) = dw; - dw = CAMELLIA_SUBKEY_L(22) ^ CAMELLIA_SUBKEY_R(22), - dw = CAMELLIA_RL8(dw);/* round 17 */ - CAMELLIA_SUBKEY_R(22) = CAMELLIA_SUBKEY_L(22) ^ dw, - CAMELLIA_SUBKEY_L(22) = dw; - dw = CAMELLIA_SUBKEY_L(23) ^ CAMELLIA_SUBKEY_R(23), - dw = CAMELLIA_RL8(dw);/* round 18 */ - CAMELLIA_SUBKEY_R(23) = CAMELLIA_SUBKEY_L(23) ^ dw, - CAMELLIA_SUBKEY_L(23) = dw; - dw = CAMELLIA_SUBKEY_L(26) ^ CAMELLIA_SUBKEY_R(26), - dw = CAMELLIA_RL8(dw);/* round 19 */ - CAMELLIA_SUBKEY_R(26) = CAMELLIA_SUBKEY_L(26) ^ dw, - CAMELLIA_SUBKEY_L(26) = dw; - dw = CAMELLIA_SUBKEY_L(27) ^ CAMELLIA_SUBKEY_R(27), - dw = CAMELLIA_RL8(dw);/* round 20 */ - CAMELLIA_SUBKEY_R(27) = CAMELLIA_SUBKEY_L(27) ^ dw, - CAMELLIA_SUBKEY_L(27) = dw; - dw = CAMELLIA_SUBKEY_L(28) ^ CAMELLIA_SUBKEY_R(28), - dw = CAMELLIA_RL8(dw);/* round 21 */ - CAMELLIA_SUBKEY_R(28) = CAMELLIA_SUBKEY_L(28) ^ dw, - CAMELLIA_SUBKEY_L(28) = dw; - dw = CAMELLIA_SUBKEY_L(29) ^ CAMELLIA_SUBKEY_R(29), - dw = CAMELLIA_RL8(dw);/* round 22 */ - CAMELLIA_SUBKEY_R(29) = CAMELLIA_SUBKEY_L(29) ^ dw, - CAMELLIA_SUBKEY_L(29) = dw; - dw = CAMELLIA_SUBKEY_L(30) ^ CAMELLIA_SUBKEY_R(30), - dw = CAMELLIA_RL8(dw);/* round 23 */ - CAMELLIA_SUBKEY_R(30) = CAMELLIA_SUBKEY_L(30) ^ dw, - CAMELLIA_SUBKEY_L(30) = dw; - dw = CAMELLIA_SUBKEY_L(31) ^ CAMELLIA_SUBKEY_R(31), - dw = CAMELLIA_RL8(dw);/* round 24 */ - CAMELLIA_SUBKEY_R(31) = CAMELLIA_SUBKEY_L(31) ^ dw, - CAMELLIA_SUBKEY_L(31) = dw; - - return; + camellia_setup_tail(subkey, subL, subR, 32); } static void camellia_setup192(const unsigned char *key, u32 *subkey) @@ -1197,482 +850,168 @@ static void camellia_setup192(const unsigned char *key, u32 *subkey) u32 krll, krlr, krrl,krrr; memcpy(kk, key, 24); - memcpy((unsigned char *)&krll, key+16,4); - memcpy((unsigned char *)&krlr, key+20,4); + memcpy((unsigned char *)&krll, key+16, 4); + memcpy((unsigned char *)&krlr, key+20, 4); krrl = ~krll; krrr = ~krlr; memcpy(kk+24, (unsigned char *)&krrl, 4); memcpy(kk+28, (unsigned char *)&krrr, 4); camellia_setup256(kk, subkey); - return; } -/** - * Stuff related to camellia encryption/decryption +/* + * Encrypt/decrypt */ -static void camellia_encrypt128(const u32 *subkey, __be32 *io_text) -{ - u32 il,ir,t0,t1; /* temporary valiables */ - - u32 io[4]; - - io[0] = be32_to_cpu(io_text[0]); - io[1] = be32_to_cpu(io_text[1]); - io[2] = be32_to_cpu(io_text[2]); - io[3] = be32_to_cpu(io_text[3]); - - /* pre whitening but absorb kw2*/ - io[0] ^= CAMELLIA_SUBKEY_L(0); - io[1] ^= CAMELLIA_SUBKEY_R(0); - /* main iteration */ - - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(2),CAMELLIA_SUBKEY_R(2), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(3),CAMELLIA_SUBKEY_R(3), - io[0],io[1],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(4),CAMELLIA_SUBKEY_R(4), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(5),CAMELLIA_SUBKEY_R(5), - io[0],io[1],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(6),CAMELLIA_SUBKEY_R(6), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(7),CAMELLIA_SUBKEY_R(7), - io[0],io[1],il,ir,t0,t1); - - CAMELLIA_FLS(io[0],io[1],io[2],io[3], - CAMELLIA_SUBKEY_L(8),CAMELLIA_SUBKEY_R(8), - CAMELLIA_SUBKEY_L(9),CAMELLIA_SUBKEY_R(9), - t0,t1,il,ir); - - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(10),CAMELLIA_SUBKEY_R(10), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(11),CAMELLIA_SUBKEY_R(11), - io[0],io[1],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(12),CAMELLIA_SUBKEY_R(12), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(13),CAMELLIA_SUBKEY_R(13), - io[0],io[1],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(14),CAMELLIA_SUBKEY_R(14), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(15),CAMELLIA_SUBKEY_R(15), - io[0],io[1],il,ir,t0,t1); - - CAMELLIA_FLS(io[0],io[1],io[2],io[3], - CAMELLIA_SUBKEY_L(16),CAMELLIA_SUBKEY_R(16), - CAMELLIA_SUBKEY_L(17),CAMELLIA_SUBKEY_R(17), - t0,t1,il,ir); - - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(18),CAMELLIA_SUBKEY_R(18), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(19),CAMELLIA_SUBKEY_R(19), - io[0],io[1],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(20),CAMELLIA_SUBKEY_R(20), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(21),CAMELLIA_SUBKEY_R(21), - io[0],io[1],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(22),CAMELLIA_SUBKEY_R(22), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(23),CAMELLIA_SUBKEY_R(23), - io[0],io[1],il,ir,t0,t1); +#define CAMELLIA_FLS(ll, lr, rl, rr, kll, klr, krl, krr, t0, t1, t2, t3) \ + do { \ + t0 = kll; \ + t2 = krr; \ + t0 &= ll; \ + t2 |= rr; \ + rl ^= t2; \ + lr ^= ROL1(t0); \ + t3 = krl; \ + t1 = klr; \ + t3 &= rl; \ + t1 |= lr; \ + ll ^= t1; \ + rr ^= ROL1(t3); \ + } while(0) - /* post whitening but kw4 */ - io[2] ^= CAMELLIA_SUBKEY_L(24); - io[3] ^= CAMELLIA_SUBKEY_R(24); - - t0 = io[0]; - t1 = io[1]; - io[0] = io[2]; - io[1] = io[3]; - io[2] = t0; - io[3] = t1; - - io_text[0] = cpu_to_be32(io[0]); - io_text[1] = cpu_to_be32(io[1]); - io_text[2] = cpu_to_be32(io[2]); - io_text[3] = cpu_to_be32(io[3]); - - return; -} +#define CAMELLIA_ROUNDSM(xl, xr, kl, kr, yl, yr, il, ir) \ + do { \ + ir = camellia_sp1110[(u8)xr]; \ + il = camellia_sp1110[ (xl >> 24)]; \ + ir ^= camellia_sp0222[ (xr >> 24)]; \ + il ^= camellia_sp0222[(u8)(xl >> 16)]; \ + ir ^= camellia_sp3033[(u8)(xr >> 16)]; \ + il ^= camellia_sp3033[(u8)(xl >> 8)]; \ + ir ^= camellia_sp4404[(u8)(xr >> 8)]; \ + il ^= camellia_sp4404[(u8)xl]; \ + il ^= kl; \ + ir ^= il ^ kr; \ + yl ^= ir; \ + yr ^= ROR8(il) ^ ir; \ + } while(0) -static void camellia_decrypt128(const u32 *subkey, __be32 *io_text) +/* max = 24: 128bit encrypt, max = 32: 256bit encrypt */ +static void camellia_do_encrypt(const u32 *subkey, u32 *io, unsigned max) { - u32 il,ir,t0,t1; /* temporary valiables */ + u32 il,ir,t0,t1; /* temporary variables */ - u32 io[4]; - - io[0] = be32_to_cpu(io_text[0]); - io[1] = be32_to_cpu(io_text[1]); - io[2] = be32_to_cpu(io_text[2]); - io[3] = be32_to_cpu(io_text[3]); - - /* pre whitening but absorb kw2*/ - io[0] ^= CAMELLIA_SUBKEY_L(24); - io[1] ^= CAMELLIA_SUBKEY_R(24); + /* pre whitening but absorb kw2 */ + io[0] ^= SUBKEY_L(0); + io[1] ^= SUBKEY_R(0); /* main iteration */ - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(23),CAMELLIA_SUBKEY_R(23), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(22),CAMELLIA_SUBKEY_R(22), - io[0],io[1],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(21),CAMELLIA_SUBKEY_R(21), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(20),CAMELLIA_SUBKEY_R(20), - io[0],io[1],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(19),CAMELLIA_SUBKEY_R(19), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(18),CAMELLIA_SUBKEY_R(18), - io[0],io[1],il,ir,t0,t1); - - CAMELLIA_FLS(io[0],io[1],io[2],io[3], - CAMELLIA_SUBKEY_L(17),CAMELLIA_SUBKEY_R(17), - CAMELLIA_SUBKEY_L(16),CAMELLIA_SUBKEY_R(16), - t0,t1,il,ir); - - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(15),CAMELLIA_SUBKEY_R(15), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(14),CAMELLIA_SUBKEY_R(14), - io[0],io[1],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(13),CAMELLIA_SUBKEY_R(13), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(12),CAMELLIA_SUBKEY_R(12), - io[0],io[1],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(11),CAMELLIA_SUBKEY_R(11), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(10),CAMELLIA_SUBKEY_R(10), - io[0],io[1],il,ir,t0,t1); - - CAMELLIA_FLS(io[0],io[1],io[2],io[3], - CAMELLIA_SUBKEY_L(9),CAMELLIA_SUBKEY_R(9), - CAMELLIA_SUBKEY_L(8),CAMELLIA_SUBKEY_R(8), - t0,t1,il,ir); - - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(7),CAMELLIA_SUBKEY_R(7), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(6),CAMELLIA_SUBKEY_R(6), - io[0],io[1],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(5),CAMELLIA_SUBKEY_R(5), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(4),CAMELLIA_SUBKEY_R(4), - io[0],io[1],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(3),CAMELLIA_SUBKEY_R(3), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(2),CAMELLIA_SUBKEY_R(2), - io[0],io[1],il,ir,t0,t1); - - /* post whitening but kw4 */ - io[2] ^= CAMELLIA_SUBKEY_L(0); - io[3] ^= CAMELLIA_SUBKEY_R(0); - - t0 = io[0]; - t1 = io[1]; - io[0] = io[2]; - io[1] = io[3]; - io[2] = t0; - io[3] = t1; - - io_text[0] = cpu_to_be32(io[0]); - io_text[1] = cpu_to_be32(io[1]); - io_text[2] = cpu_to_be32(io[2]); - io_text[3] = cpu_to_be32(io[3]); - - return; -} - - -/** - * stuff for 192 and 256bit encryption/decryption - */ -static void camellia_encrypt256(const u32 *subkey, __be32 *io_text) -{ - u32 il,ir,t0,t1; /* temporary valiables */ - - u32 io[4]; - - io[0] = be32_to_cpu(io_text[0]); - io[1] = be32_to_cpu(io_text[1]); - io[2] = be32_to_cpu(io_text[2]); - io[3] = be32_to_cpu(io_text[3]); +#define ROUNDS(i) do { \ + CAMELLIA_ROUNDSM(io[0],io[1], \ + SUBKEY_L(i + 2),SUBKEY_R(i + 2), \ + io[2],io[3],il,ir); \ + CAMELLIA_ROUNDSM(io[2],io[3], \ + SUBKEY_L(i + 3),SUBKEY_R(i + 3), \ + io[0],io[1],il,ir); \ + CAMELLIA_ROUNDSM(io[0],io[1], \ + SUBKEY_L(i + 4),SUBKEY_R(i + 4), \ + io[2],io[3],il,ir); \ + CAMELLIA_ROUNDSM(io[2],io[3], \ + SUBKEY_L(i + 5),SUBKEY_R(i + 5), \ + io[0],io[1],il,ir); \ + CAMELLIA_ROUNDSM(io[0],io[1], \ + SUBKEY_L(i + 6),SUBKEY_R(i + 6), \ + io[2],io[3],il,ir); \ + CAMELLIA_ROUNDSM(io[2],io[3], \ + SUBKEY_L(i + 7),SUBKEY_R(i + 7), \ + io[0],io[1],il,ir); \ +} while (0) +#define FLS(i) do { \ + CAMELLIA_FLS(io[0],io[1],io[2],io[3], \ + SUBKEY_L(i + 0),SUBKEY_R(i + 0), \ + SUBKEY_L(i + 1),SUBKEY_R(i + 1), \ + t0,t1,il,ir); \ +} while (0) + + ROUNDS(0); + FLS(8); + ROUNDS(8); + FLS(16); + ROUNDS(16); + if (max == 32) { + FLS(24); + ROUNDS(24); + } - /* pre whitening but absorb kw2*/ - io[0] ^= CAMELLIA_SUBKEY_L(0); - io[1] ^= CAMELLIA_SUBKEY_R(0); - - /* main iteration */ - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(2),CAMELLIA_SUBKEY_R(2), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(3),CAMELLIA_SUBKEY_R(3), - io[0],io[1],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(4),CAMELLIA_SUBKEY_R(4), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(5),CAMELLIA_SUBKEY_R(5), - io[0],io[1],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(6),CAMELLIA_SUBKEY_R(6), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(7),CAMELLIA_SUBKEY_R(7), - io[0],io[1],il,ir,t0,t1); - - CAMELLIA_FLS(io[0],io[1],io[2],io[3], - CAMELLIA_SUBKEY_L(8),CAMELLIA_SUBKEY_R(8), - CAMELLIA_SUBKEY_L(9),CAMELLIA_SUBKEY_R(9), - t0,t1,il,ir); - - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(10),CAMELLIA_SUBKEY_R(10), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(11),CAMELLIA_SUBKEY_R(11), - io[0],io[1],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(12),CAMELLIA_SUBKEY_R(12), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(13),CAMELLIA_SUBKEY_R(13), - io[0],io[1],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(14),CAMELLIA_SUBKEY_R(14), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(15),CAMELLIA_SUBKEY_R(15), - io[0],io[1],il,ir,t0,t1); - - CAMELLIA_FLS(io[0],io[1],io[2],io[3], - CAMELLIA_SUBKEY_L(16),CAMELLIA_SUBKEY_R(16), - CAMELLIA_SUBKEY_L(17),CAMELLIA_SUBKEY_R(17), - t0,t1,il,ir); - - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(18),CAMELLIA_SUBKEY_R(18), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(19),CAMELLIA_SUBKEY_R(19), - io[0],io[1],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(20),CAMELLIA_SUBKEY_R(20), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(21),CAMELLIA_SUBKEY_R(21), - io[0],io[1],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(22),CAMELLIA_SUBKEY_R(22), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(23),CAMELLIA_SUBKEY_R(23), - io[0],io[1],il,ir,t0,t1); - - CAMELLIA_FLS(io[0],io[1],io[2],io[3], - CAMELLIA_SUBKEY_L(24),CAMELLIA_SUBKEY_R(24), - CAMELLIA_SUBKEY_L(25),CAMELLIA_SUBKEY_R(25), - t0,t1,il,ir); - - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(26),CAMELLIA_SUBKEY_R(26), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(27),CAMELLIA_SUBKEY_R(27), - io[0],io[1],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(28),CAMELLIA_SUBKEY_R(28), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(29),CAMELLIA_SUBKEY_R(29), - io[0],io[1],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(30),CAMELLIA_SUBKEY_R(30), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(31),CAMELLIA_SUBKEY_R(31), - io[0],io[1],il,ir,t0,t1); +#undef ROUNDS +#undef FLS /* post whitening but kw4 */ - io[2] ^= CAMELLIA_SUBKEY_L(32); - io[3] ^= CAMELLIA_SUBKEY_R(32); - - t0 = io[0]; - t1 = io[1]; - io[0] = io[2]; - io[1] = io[3]; - io[2] = t0; - io[3] = t1; - - io_text[0] = cpu_to_be32(io[0]); - io_text[1] = cpu_to_be32(io[1]); - io_text[2] = cpu_to_be32(io[2]); - io_text[3] = cpu_to_be32(io[3]); - - return; + io[2] ^= SUBKEY_L(max); + io[3] ^= SUBKEY_R(max); + /* NB: io[0],[1] should be swapped with [2],[3] by caller! */ } - -static void camellia_decrypt256(const u32 *subkey, __be32 *io_text) +static void camellia_do_decrypt(const u32 *subkey, u32 *io, unsigned i) { - u32 il,ir,t0,t1; /* temporary valiables */ + u32 il,ir,t0,t1; /* temporary variables */ - u32 io[4]; - - io[0] = be32_to_cpu(io_text[0]); - io[1] = be32_to_cpu(io_text[1]); - io[2] = be32_to_cpu(io_text[2]); - io[3] = be32_to_cpu(io_text[3]); - - /* pre whitening but absorb kw2*/ - io[0] ^= CAMELLIA_SUBKEY_L(32); - io[1] ^= CAMELLIA_SUBKEY_R(32); + /* pre whitening but absorb kw2 */ + io[0] ^= SUBKEY_L(i); + io[1] ^= SUBKEY_R(i); /* main iteration */ - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(31),CAMELLIA_SUBKEY_R(31), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(30),CAMELLIA_SUBKEY_R(30), - io[0],io[1],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(29),CAMELLIA_SUBKEY_R(29), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(28),CAMELLIA_SUBKEY_R(28), - io[0],io[1],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(27),CAMELLIA_SUBKEY_R(27), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(26),CAMELLIA_SUBKEY_R(26), - io[0],io[1],il,ir,t0,t1); - - CAMELLIA_FLS(io[0],io[1],io[2],io[3], - CAMELLIA_SUBKEY_L(25),CAMELLIA_SUBKEY_R(25), - CAMELLIA_SUBKEY_L(24),CAMELLIA_SUBKEY_R(24), - t0,t1,il,ir); - - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(23),CAMELLIA_SUBKEY_R(23), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(22),CAMELLIA_SUBKEY_R(22), - io[0],io[1],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(21),CAMELLIA_SUBKEY_R(21), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(20),CAMELLIA_SUBKEY_R(20), - io[0],io[1],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(19),CAMELLIA_SUBKEY_R(19), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(18),CAMELLIA_SUBKEY_R(18), - io[0],io[1],il,ir,t0,t1); - - CAMELLIA_FLS(io[0],io[1],io[2],io[3], - CAMELLIA_SUBKEY_L(17),CAMELLIA_SUBKEY_R(17), - CAMELLIA_SUBKEY_L(16),CAMELLIA_SUBKEY_R(16), - t0,t1,il,ir); - - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(15),CAMELLIA_SUBKEY_R(15), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(14),CAMELLIA_SUBKEY_R(14), - io[0],io[1],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(13),CAMELLIA_SUBKEY_R(13), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(12),CAMELLIA_SUBKEY_R(12), - io[0],io[1],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(11),CAMELLIA_SUBKEY_R(11), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(10),CAMELLIA_SUBKEY_R(10), - io[0],io[1],il,ir,t0,t1); - - CAMELLIA_FLS(io[0],io[1],io[2],io[3], - CAMELLIA_SUBKEY_L(9),CAMELLIA_SUBKEY_R(9), - CAMELLIA_SUBKEY_L(8),CAMELLIA_SUBKEY_R(8), - t0,t1,il,ir); - - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(7),CAMELLIA_SUBKEY_R(7), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(6),CAMELLIA_SUBKEY_R(6), - io[0],io[1],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(5),CAMELLIA_SUBKEY_R(5), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(4),CAMELLIA_SUBKEY_R(4), - io[0],io[1],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[0],io[1], - CAMELLIA_SUBKEY_L(3),CAMELLIA_SUBKEY_R(3), - io[2],io[3],il,ir,t0,t1); - CAMELLIA_ROUNDSM(io[2],io[3], - CAMELLIA_SUBKEY_L(2),CAMELLIA_SUBKEY_R(2), - io[0],io[1],il,ir,t0,t1); +#define ROUNDS(i) do { \ + CAMELLIA_ROUNDSM(io[0],io[1], \ + SUBKEY_L(i + 7),SUBKEY_R(i + 7), \ + io[2],io[3],il,ir); \ + CAMELLIA_ROUNDSM(io[2],io[3], \ + SUBKEY_L(i + 6),SUBKEY_R(i + 6), \ + io[0],io[1],il,ir); \ + CAMELLIA_ROUNDSM(io[0],io[1], \ + SUBKEY_L(i + 5),SUBKEY_R(i + 5), \ + io[2],io[3],il,ir); \ + CAMELLIA_ROUNDSM(io[2],io[3], \ + SUBKEY_L(i + 4),SUBKEY_R(i + 4), \ + io[0],io[1],il,ir); \ + CAMELLIA_ROUNDSM(io[0],io[1], \ + SUBKEY_L(i + 3),SUBKEY_R(i + 3), \ + io[2],io[3],il,ir); \ + CAMELLIA_ROUNDSM(io[2],io[3], \ + SUBKEY_L(i + 2),SUBKEY_R(i + 2), \ + io[0],io[1],il,ir); \ +} while (0) +#define FLS(i) do { \ + CAMELLIA_FLS(io[0],io[1],io[2],io[3], \ + SUBKEY_L(i + 1),SUBKEY_R(i + 1), \ + SUBKEY_L(i + 0),SUBKEY_R(i + 0), \ + t0,t1,il,ir); \ +} while (0) + + if (i == 32) { + ROUNDS(24); + FLS(24); + } + ROUNDS(16); + FLS(16); + ROUNDS(8); + FLS(8); + ROUNDS(0); + +#undef ROUNDS +#undef FLS /* post whitening but kw4 */ - io[2] ^= CAMELLIA_SUBKEY_L(0); - io[3] ^= CAMELLIA_SUBKEY_R(0); - - t0 = io[0]; - t1 = io[1]; - io[0] = io[2]; - io[1] = io[3]; - io[2] = t0; - io[3] = t1; - - io_text[0] = cpu_to_be32(io[0]); - io_text[1] = cpu_to_be32(io[1]); - io_text[2] = cpu_to_be32(io[2]); - io_text[3] = cpu_to_be32(io[3]); - - return; + io[2] ^= SUBKEY_L(0); + io[3] ^= SUBKEY_R(0); + /* NB: 0,1 should be swapped with 2,3 by caller! */ } +struct camellia_ctx { + int key_length; + u32 key_table[CAMELLIA_TABLE_BYTE_LEN / sizeof(u32)]; +}; + static int camellia_set_key(struct crypto_tfm *tfm, const u8 *in_key, unsigned int key_len) @@ -1688,7 +1027,7 @@ camellia_set_key(struct crypto_tfm *tfm, const u8 *in_key, cctx->key_length = key_len; - switch(key_len) { + switch (key_len) { case 16: camellia_setup128(key, cctx->key_table); break; @@ -1698,68 +1037,59 @@ camellia_set_key(struct crypto_tfm *tfm, const u8 *in_key, case 32: camellia_setup256(key, cctx->key_table); break; - default: - break; } return 0; } - static void camellia_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { const struct camellia_ctx *cctx = crypto_tfm_ctx(tfm); const __be32 *src = (const __be32 *)in; __be32 *dst = (__be32 *)out; - __be32 tmp[4]; + u32 tmp[4]; - memcpy(tmp, src, CAMELLIA_BLOCK_SIZE); + tmp[0] = be32_to_cpu(src[0]); + tmp[1] = be32_to_cpu(src[1]); + tmp[2] = be32_to_cpu(src[2]); + tmp[3] = be32_to_cpu(src[3]); - switch (cctx->key_length) { - case 16: - camellia_encrypt128(cctx->key_table, tmp); - break; - case 24: - /* fall through */ - case 32: - camellia_encrypt256(cctx->key_table, tmp); - break; - default: - break; - } + camellia_do_encrypt(cctx->key_table, tmp, + cctx->key_length == 16 ? 24 : 32 /* for key lengths of 24 and 32 */ + ); - memcpy(dst, tmp, CAMELLIA_BLOCK_SIZE); + /* do_encrypt returns 0,1 swapped with 2,3 */ + dst[0] = cpu_to_be32(tmp[2]); + dst[1] = cpu_to_be32(tmp[3]); + dst[2] = cpu_to_be32(tmp[0]); + dst[3] = cpu_to_be32(tmp[1]); } - static void camellia_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { const struct camellia_ctx *cctx = crypto_tfm_ctx(tfm); const __be32 *src = (const __be32 *)in; __be32 *dst = (__be32 *)out; - __be32 tmp[4]; + u32 tmp[4]; - memcpy(tmp, src, CAMELLIA_BLOCK_SIZE); + tmp[0] = be32_to_cpu(src[0]); + tmp[1] = be32_to_cpu(src[1]); + tmp[2] = be32_to_cpu(src[2]); + tmp[3] = be32_to_cpu(src[3]); - switch (cctx->key_length) { - case 16: - camellia_decrypt128(cctx->key_table, tmp); - break; - case 24: - /* fall through */ - case 32: - camellia_decrypt256(cctx->key_table, tmp); - break; - default: - break; - } + camellia_do_decrypt(cctx->key_table, tmp, + cctx->key_length == 16 ? 24 : 32 /* for key lengths of 24 and 32 */ + ); - memcpy(dst, tmp, CAMELLIA_BLOCK_SIZE); + /* do_decrypt returns 0,1 swapped with 2,3 */ + dst[0] = cpu_to_be32(tmp[2]); + dst[1] = cpu_to_be32(tmp[3]); + dst[2] = cpu_to_be32(tmp[0]); + dst[3] = cpu_to_be32(tmp[1]); } - static struct crypto_alg camellia_alg = { .cra_name = "camellia", .cra_driver_name = "camellia-generic", @@ -1786,16 +1116,13 @@ static int __init camellia_init(void) return crypto_register_alg(&camellia_alg); } - static void __exit camellia_fini(void) { crypto_unregister_alg(&camellia_alg); } - module_init(camellia_init); module_exit(camellia_fini); - MODULE_DESCRIPTION("Camellia Cipher Algorithm"); MODULE_LICENSE("GPL"); diff --git a/crypto/cast6.c b/crypto/cast6.c index 136ab6dfe8c5..5fd9420dc58e 100644 --- a/crypto/cast6.c +++ b/crypto/cast6.c @@ -369,7 +369,7 @@ static const u8 Tr[4][8] = { }; /* forward octave */ -static inline void W(u32 *key, unsigned int i) { +static void W(u32 *key, unsigned int i) { u32 I; key[6] ^= F1(key[7], Tr[i % 4][0], Tm[i][0]); key[5] ^= F2(key[6], Tr[i % 4][1], Tm[i][1]); @@ -428,7 +428,7 @@ static int cast6_setkey(struct crypto_tfm *tfm, const u8 *in_key, } /*forward quad round*/ -static inline void Q (u32 * block, u8 * Kr, u32 * Km) { +static void Q (u32 * block, u8 * Kr, u32 * Km) { u32 I; block[2] ^= F1(block[3], Kr[0], Km[0]); block[1] ^= F2(block[2], Kr[1], Km[1]); @@ -437,7 +437,7 @@ static inline void Q (u32 * block, u8 * Kr, u32 * Km) { } /*reverse quad round*/ -static inline void QBAR (u32 * block, u8 * Kr, u32 * Km) { +static void QBAR (u32 * block, u8 * Kr, u32 * Km) { u32 I; block[3] ^= F1(block[0], Kr[3], Km[3]); block[0] ^= F3(block[1], Kr[2], Km[2]); diff --git a/crypto/cbc.c b/crypto/cbc.c index 1f2649e13b42..6affff882cf8 100644 --- a/crypto/cbc.c +++ b/crypto/cbc.c @@ -14,13 +14,13 @@ #include <linux/err.h> #include <linux/init.h> #include <linux/kernel.h> +#include <linux/log2.h> #include <linux/module.h> #include <linux/scatterlist.h> #include <linux/slab.h> struct crypto_cbc_ctx { struct crypto_cipher *child; - void (*xor)(u8 *dst, const u8 *src, unsigned int bs); }; static int crypto_cbc_setkey(struct crypto_tfm *parent, const u8 *key, @@ -41,9 +41,7 @@ static int crypto_cbc_setkey(struct crypto_tfm *parent, const u8 *key, static int crypto_cbc_encrypt_segment(struct blkcipher_desc *desc, struct blkcipher_walk *walk, - struct crypto_cipher *tfm, - void (*xor)(u8 *, const u8 *, - unsigned int)) + struct crypto_cipher *tfm) { void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = crypto_cipher_alg(tfm)->cia_encrypt; @@ -54,7 +52,7 @@ static int crypto_cbc_encrypt_segment(struct blkcipher_desc *desc, u8 *iv = walk->iv; do { - xor(iv, src, bsize); + crypto_xor(iv, src, bsize); fn(crypto_cipher_tfm(tfm), dst, iv); memcpy(iv, dst, bsize); @@ -67,9 +65,7 @@ static int crypto_cbc_encrypt_segment(struct blkcipher_desc *desc, static int crypto_cbc_encrypt_inplace(struct blkcipher_desc *desc, struct blkcipher_walk *walk, - struct crypto_cipher *tfm, - void (*xor)(u8 *, const u8 *, - unsigned int)) + struct crypto_cipher *tfm) { void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = crypto_cipher_alg(tfm)->cia_encrypt; @@ -79,7 +75,7 @@ static int crypto_cbc_encrypt_inplace(struct blkcipher_desc *desc, u8 *iv = walk->iv; do { - xor(src, iv, bsize); + crypto_xor(src, iv, bsize); fn(crypto_cipher_tfm(tfm), src, src); iv = src; @@ -99,7 +95,6 @@ static int crypto_cbc_encrypt(struct blkcipher_desc *desc, struct crypto_blkcipher *tfm = desc->tfm; struct crypto_cbc_ctx *ctx = crypto_blkcipher_ctx(tfm); struct crypto_cipher *child = ctx->child; - void (*xor)(u8 *, const u8 *, unsigned int bs) = ctx->xor; int err; blkcipher_walk_init(&walk, dst, src, nbytes); @@ -107,11 +102,9 @@ static int crypto_cbc_encrypt(struct blkcipher_desc *desc, while ((nbytes = walk.nbytes)) { if (walk.src.virt.addr == walk.dst.virt.addr) - nbytes = crypto_cbc_encrypt_inplace(desc, &walk, child, - xor); + nbytes = crypto_cbc_encrypt_inplace(desc, &walk, child); else - nbytes = crypto_cbc_encrypt_segment(desc, &walk, child, - xor); + nbytes = crypto_cbc_encrypt_segment(desc, &walk, child); err = blkcipher_walk_done(desc, &walk, nbytes); } @@ -120,9 +113,7 @@ static int crypto_cbc_encrypt(struct blkcipher_desc *desc, static int crypto_cbc_decrypt_segment(struct blkcipher_desc *desc, struct blkcipher_walk *walk, - struct crypto_cipher *tfm, - void (*xor)(u8 *, const u8 *, - unsigned int)) + struct crypto_cipher *tfm) { void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = crypto_cipher_alg(tfm)->cia_decrypt; @@ -134,7 +125,7 @@ static int crypto_cbc_decrypt_segment(struct blkcipher_desc *desc, do { fn(crypto_cipher_tfm(tfm), dst, src); - xor(dst, iv, bsize); + crypto_xor(dst, iv, bsize); iv = src; src += bsize; @@ -148,34 +139,29 @@ static int crypto_cbc_decrypt_segment(struct blkcipher_desc *desc, static int crypto_cbc_decrypt_inplace(struct blkcipher_desc *desc, struct blkcipher_walk *walk, - struct crypto_cipher *tfm, - void (*xor)(u8 *, const u8 *, - unsigned int)) + struct crypto_cipher *tfm) { void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = crypto_cipher_alg(tfm)->cia_decrypt; int bsize = crypto_cipher_blocksize(tfm); - unsigned long alignmask = crypto_cipher_alignmask(tfm); unsigned int nbytes = walk->nbytes; u8 *src = walk->src.virt.addr; - u8 stack[bsize + alignmask]; - u8 *first_iv = (u8 *)ALIGN((unsigned long)stack, alignmask + 1); - - memcpy(first_iv, walk->iv, bsize); + u8 last_iv[bsize]; /* Start of the last block. */ - src += nbytes - nbytes % bsize - bsize; - memcpy(walk->iv, src, bsize); + src += nbytes - (nbytes & (bsize - 1)) - bsize; + memcpy(last_iv, src, bsize); for (;;) { fn(crypto_cipher_tfm(tfm), src, src); if ((nbytes -= bsize) < bsize) break; - xor(src, src - bsize, bsize); + crypto_xor(src, src - bsize, bsize); src -= bsize; } - xor(src, first_iv, bsize); + crypto_xor(src, walk->iv, bsize); + memcpy(walk->iv, last_iv, bsize); return nbytes; } @@ -188,7 +174,6 @@ static int crypto_cbc_decrypt(struct blkcipher_desc *desc, struct crypto_blkcipher *tfm = desc->tfm; struct crypto_cbc_ctx *ctx = crypto_blkcipher_ctx(tfm); struct crypto_cipher *child = ctx->child; - void (*xor)(u8 *, const u8 *, unsigned int bs) = ctx->xor; int err; blkcipher_walk_init(&walk, dst, src, nbytes); @@ -196,48 +181,15 @@ static int crypto_cbc_decrypt(struct blkcipher_desc *desc, while ((nbytes = walk.nbytes)) { if (walk.src.virt.addr == walk.dst.virt.addr) - nbytes = crypto_cbc_decrypt_inplace(desc, &walk, child, - xor); + nbytes = crypto_cbc_decrypt_inplace(desc, &walk, child); else - nbytes = crypto_cbc_decrypt_segment(desc, &walk, child, - xor); + nbytes = crypto_cbc_decrypt_segment(desc, &walk, child); err = blkcipher_walk_done(desc, &walk, nbytes); } return err; } -static void xor_byte(u8 *a, const u8 *b, unsigned int bs) -{ - do { - *a++ ^= *b++; - } while (--bs); -} - -static void xor_quad(u8 *dst, const u8 *src, unsigned int bs) -{ - u32 *a = (u32 *)dst; - u32 *b = (u32 *)src; - - do { - *a++ ^= *b++; - } while ((bs -= 4)); -} - -static void xor_64(u8 *a, const u8 *b, unsigned int bs) -{ - ((u32 *)a)[0] ^= ((u32 *)b)[0]; - ((u32 *)a)[1] ^= ((u32 *)b)[1]; -} - -static void xor_128(u8 *a, const u8 *b, unsigned int bs) -{ - ((u32 *)a)[0] ^= ((u32 *)b)[0]; - ((u32 *)a)[1] ^= ((u32 *)b)[1]; - ((u32 *)a)[2] ^= ((u32 *)b)[2]; - ((u32 *)a)[3] ^= ((u32 *)b)[3]; -} - static int crypto_cbc_init_tfm(struct crypto_tfm *tfm) { struct crypto_instance *inst = (void *)tfm->__crt_alg; @@ -245,22 +197,6 @@ static int crypto_cbc_init_tfm(struct crypto_tfm *tfm) struct crypto_cbc_ctx *ctx = crypto_tfm_ctx(tfm); struct crypto_cipher *cipher; - switch (crypto_tfm_alg_blocksize(tfm)) { - case 8: - ctx->xor = xor_64; - break; - - case 16: - ctx->xor = xor_128; - break; - - default: - if (crypto_tfm_alg_blocksize(tfm) % 4) - ctx->xor = xor_byte; - else - ctx->xor = xor_quad; - } - cipher = crypto_spawn_cipher(spawn); if (IS_ERR(cipher)) return PTR_ERR(cipher); @@ -290,6 +226,10 @@ static struct crypto_instance *crypto_cbc_alloc(struct rtattr **tb) if (IS_ERR(alg)) return ERR_PTR(PTR_ERR(alg)); + inst = ERR_PTR(-EINVAL); + if (!is_power_of_2(alg->cra_blocksize)) + goto out_put_alg; + inst = crypto_alloc_instance("cbc", alg); if (IS_ERR(inst)) goto out_put_alg; @@ -300,8 +240,9 @@ static struct crypto_instance *crypto_cbc_alloc(struct rtattr **tb) inst->alg.cra_alignmask = alg->cra_alignmask; inst->alg.cra_type = &crypto_blkcipher_type; - if (!(alg->cra_blocksize % 4)) - inst->alg.cra_alignmask |= 3; + /* We access the data as u32s when xoring. */ + inst->alg.cra_alignmask |= __alignof__(u32) - 1; + inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize; inst->alg.cra_blkcipher.min_keysize = alg->cra_cipher.cia_min_keysize; inst->alg.cra_blkcipher.max_keysize = alg->cra_cipher.cia_max_keysize; diff --git a/crypto/ccm.c b/crypto/ccm.c new file mode 100644 index 000000000000..7cf7e5a6b781 --- /dev/null +++ b/crypto/ccm.c @@ -0,0 +1,889 @@ +/* + * CCM: Counter with CBC-MAC + * + * (C) Copyright IBM Corp. 2007 - Joy Latten <latten@us.ibm.com> + * + * 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. + * + */ + +#include <crypto/internal/aead.h> +#include <crypto/internal/skcipher.h> +#include <crypto/scatterwalk.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> + +#include "internal.h" + +struct ccm_instance_ctx { + struct crypto_skcipher_spawn ctr; + struct crypto_spawn cipher; +}; + +struct crypto_ccm_ctx { + struct crypto_cipher *cipher; + struct crypto_ablkcipher *ctr; +}; + +struct crypto_rfc4309_ctx { + struct crypto_aead *child; + u8 nonce[3]; +}; + +struct crypto_ccm_req_priv_ctx { + u8 odata[16]; + u8 idata[16]; + u8 auth_tag[16]; + u32 ilen; + u32 flags; + struct scatterlist src[2]; + struct scatterlist dst[2]; + struct ablkcipher_request abreq; +}; + +static inline struct crypto_ccm_req_priv_ctx *crypto_ccm_reqctx( + struct aead_request *req) +{ + unsigned long align = crypto_aead_alignmask(crypto_aead_reqtfm(req)); + + return (void *)PTR_ALIGN((u8 *)aead_request_ctx(req), align + 1); +} + +static int set_msg_len(u8 *block, unsigned int msglen, int csize) +{ + __be32 data; + + memset(block, 0, csize); + block += csize; + + if (csize >= 4) + csize = 4; + else if (msglen > (1 << (8 * csize))) + return -EOVERFLOW; + + data = cpu_to_be32(msglen); + memcpy(block - csize, (u8 *)&data + 4 - csize, csize); + + return 0; +} + +static int crypto_ccm_setkey(struct crypto_aead *aead, const u8 *key, + unsigned int keylen) +{ + struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead); + struct crypto_ablkcipher *ctr = ctx->ctr; + struct crypto_cipher *tfm = ctx->cipher; + int err = 0; + + crypto_ablkcipher_clear_flags(ctr, CRYPTO_TFM_REQ_MASK); + crypto_ablkcipher_set_flags(ctr, crypto_aead_get_flags(aead) & + CRYPTO_TFM_REQ_MASK); + err = crypto_ablkcipher_setkey(ctr, key, keylen); + crypto_aead_set_flags(aead, crypto_ablkcipher_get_flags(ctr) & + CRYPTO_TFM_RES_MASK); + if (err) + goto out; + + crypto_cipher_clear_flags(tfm, CRYPTO_TFM_REQ_MASK); + crypto_cipher_set_flags(tfm, crypto_aead_get_flags(aead) & + CRYPTO_TFM_REQ_MASK); + err = crypto_cipher_setkey(tfm, key, keylen); + crypto_aead_set_flags(aead, crypto_cipher_get_flags(tfm) & + CRYPTO_TFM_RES_MASK); + +out: + return err; +} + +static int crypto_ccm_setauthsize(struct crypto_aead *tfm, + unsigned int authsize) +{ + switch (authsize) { + case 4: + case 6: + case 8: + case 10: + case 12: + case 14: + case 16: + break; + default: + return -EINVAL; + } + + return 0; +} + +static int format_input(u8 *info, struct aead_request *req, + unsigned int cryptlen) +{ + struct crypto_aead *aead = crypto_aead_reqtfm(req); + unsigned int lp = req->iv[0]; + unsigned int l = lp + 1; + unsigned int m; + + m = crypto_aead_authsize(aead); + + memcpy(info, req->iv, 16); + + /* format control info per RFC 3610 and + * NIST Special Publication 800-38C + */ + *info |= (8 * ((m - 2) / 2)); + if (req->assoclen) + *info |= 64; + + return set_msg_len(info + 16 - l, cryptlen, l); +} + +static int format_adata(u8 *adata, unsigned int a) +{ + int len = 0; + + /* add control info for associated data + * RFC 3610 and NIST Special Publication 800-38C + */ + if (a < 65280) { + *(__be16 *)adata = cpu_to_be16(a); + len = 2; + } else { + *(__be16 *)adata = cpu_to_be16(0xfffe); + *(__be32 *)&adata[2] = cpu_to_be32(a); + len = 6; + } + + return len; +} + +static void compute_mac(struct crypto_cipher *tfm, u8 *data, int n, + struct crypto_ccm_req_priv_ctx *pctx) +{ + unsigned int bs = 16; + u8 *odata = pctx->odata; + u8 *idata = pctx->idata; + int datalen, getlen; + + datalen = n; + + /* first time in here, block may be partially filled. */ + getlen = bs - pctx->ilen; + if (datalen >= getlen) { + memcpy(idata + pctx->ilen, data, getlen); + crypto_xor(odata, idata, bs); + crypto_cipher_encrypt_one(tfm, odata, odata); + datalen -= getlen; + data += getlen; + pctx->ilen = 0; + } + + /* now encrypt rest of data */ + while (datalen >= bs) { + crypto_xor(odata, data, bs); + crypto_cipher_encrypt_one(tfm, odata, odata); + + datalen -= bs; + data += bs; + } + + /* check and see if there's leftover data that wasn't + * enough to fill a block. + */ + if (datalen) { + memcpy(idata + pctx->ilen, data, datalen); + pctx->ilen += datalen; + } +} + +static void get_data_to_compute(struct crypto_cipher *tfm, + struct crypto_ccm_req_priv_ctx *pctx, + struct scatterlist *sg, unsigned int len) +{ + struct scatter_walk walk; + u8 *data_src; + int n; + + scatterwalk_start(&walk, sg); + + while (len) { + n = scatterwalk_clamp(&walk, len); + if (!n) { + scatterwalk_start(&walk, sg_next(walk.sg)); + n = scatterwalk_clamp(&walk, len); + } + data_src = scatterwalk_map(&walk, 0); + + compute_mac(tfm, data_src, n, pctx); + len -= n; + + scatterwalk_unmap(data_src, 0); + scatterwalk_advance(&walk, n); + scatterwalk_done(&walk, 0, len); + if (len) + crypto_yield(pctx->flags); + } + + /* any leftover needs padding and then encrypted */ + if (pctx->ilen) { + int padlen; + u8 *odata = pctx->odata; + u8 *idata = pctx->idata; + + padlen = 16 - pctx->ilen; + memset(idata + pctx->ilen, 0, padlen); + crypto_xor(odata, idata, 16); + crypto_cipher_encrypt_one(tfm, odata, odata); + pctx->ilen = 0; + } +} + +static int crypto_ccm_auth(struct aead_request *req, struct scatterlist *plain, + unsigned int cryptlen) +{ + struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead); + struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req); + struct crypto_cipher *cipher = ctx->cipher; + unsigned int assoclen = req->assoclen; + u8 *odata = pctx->odata; + u8 *idata = pctx->idata; + int err; + + /* format control data for input */ + err = format_input(odata, req, cryptlen); + if (err) + goto out; + + /* encrypt first block to use as start in computing mac */ + crypto_cipher_encrypt_one(cipher, odata, odata); + + /* format associated data and compute into mac */ + if (assoclen) { + pctx->ilen = format_adata(idata, assoclen); + get_data_to_compute(cipher, pctx, req->assoc, req->assoclen); + } + + /* compute plaintext into mac */ + get_data_to_compute(cipher, pctx, plain, cryptlen); + +out: + return err; +} + +static void crypto_ccm_encrypt_done(struct crypto_async_request *areq, int err) +{ + struct aead_request *req = areq->data; + struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req); + u8 *odata = pctx->odata; + + if (!err) + scatterwalk_map_and_copy(odata, req->dst, req->cryptlen, + crypto_aead_authsize(aead), 1); + aead_request_complete(req, err); +} + +static inline int crypto_ccm_check_iv(const u8 *iv) +{ + /* 2 <= L <= 8, so 1 <= L' <= 7. */ + if (1 > iv[0] || iv[0] > 7) + return -EINVAL; + + return 0; +} + +static int crypto_ccm_encrypt(struct aead_request *req) +{ + struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead); + struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req); + struct ablkcipher_request *abreq = &pctx->abreq; + struct scatterlist *dst; + unsigned int cryptlen = req->cryptlen; + u8 *odata = pctx->odata; + u8 *iv = req->iv; + int err; + + err = crypto_ccm_check_iv(iv); + if (err) + return err; + + pctx->flags = aead_request_flags(req); + + err = crypto_ccm_auth(req, req->src, cryptlen); + if (err) + return err; + + /* Note: rfc 3610 and NIST 800-38C require counter of + * zero to encrypt auth tag. + */ + memset(iv + 15 - iv[0], 0, iv[0] + 1); + + sg_init_table(pctx->src, 2); + sg_set_buf(pctx->src, odata, 16); + scatterwalk_sg_chain(pctx->src, 2, req->src); + + dst = pctx->src; + if (req->src != req->dst) { + sg_init_table(pctx->dst, 2); + sg_set_buf(pctx->dst, odata, 16); + scatterwalk_sg_chain(pctx->dst, 2, req->dst); + dst = pctx->dst; + } + + ablkcipher_request_set_tfm(abreq, ctx->ctr); + ablkcipher_request_set_callback(abreq, pctx->flags, + crypto_ccm_encrypt_done, req); + ablkcipher_request_set_crypt(abreq, pctx->src, dst, cryptlen + 16, iv); + err = crypto_ablkcipher_encrypt(abreq); + if (err) + return err; + + /* copy authtag to end of dst */ + scatterwalk_map_and_copy(odata, req->dst, cryptlen, + crypto_aead_authsize(aead), 1); + return err; +} + +static void crypto_ccm_decrypt_done(struct crypto_async_request *areq, + int err) +{ + struct aead_request *req = areq->data; + struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req); + struct crypto_aead *aead = crypto_aead_reqtfm(req); + unsigned int authsize = crypto_aead_authsize(aead); + unsigned int cryptlen = req->cryptlen - authsize; + + if (!err) { + err = crypto_ccm_auth(req, req->dst, cryptlen); + if (!err && memcmp(pctx->auth_tag, pctx->odata, authsize)) + err = -EBADMSG; + } + aead_request_complete(req, err); +} + +static int crypto_ccm_decrypt(struct aead_request *req) +{ + struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead); + struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req); + struct ablkcipher_request *abreq = &pctx->abreq; + struct scatterlist *dst; + unsigned int authsize = crypto_aead_authsize(aead); + unsigned int cryptlen = req->cryptlen; + u8 *authtag = pctx->auth_tag; + u8 *odata = pctx->odata; + u8 *iv = req->iv; + int err; + + if (cryptlen < authsize) + return -EINVAL; + cryptlen -= authsize; + + err = crypto_ccm_check_iv(iv); + if (err) + return err; + + pctx->flags = aead_request_flags(req); + + scatterwalk_map_and_copy(authtag, req->src, cryptlen, authsize, 0); + + memset(iv + 15 - iv[0], 0, iv[0] + 1); + + sg_init_table(pctx->src, 2); + sg_set_buf(pctx->src, authtag, 16); + scatterwalk_sg_chain(pctx->src, 2, req->src); + + dst = pctx->src; + if (req->src != req->dst) { + sg_init_table(pctx->dst, 2); + sg_set_buf(pctx->dst, authtag, 16); + scatterwalk_sg_chain(pctx->dst, 2, req->dst); + dst = pctx->dst; + } + + ablkcipher_request_set_tfm(abreq, ctx->ctr); + ablkcipher_request_set_callback(abreq, pctx->flags, + crypto_ccm_decrypt_done, req); + ablkcipher_request_set_crypt(abreq, pctx->src, dst, cryptlen + 16, iv); + err = crypto_ablkcipher_decrypt(abreq); + if (err) + return err; + + err = crypto_ccm_auth(req, req->dst, cryptlen); + if (err) + return err; + + /* verify */ + if (memcmp(authtag, odata, authsize)) + return -EBADMSG; + + return err; +} + +static int crypto_ccm_init_tfm(struct crypto_tfm *tfm) +{ + struct crypto_instance *inst = (void *)tfm->__crt_alg; + struct ccm_instance_ctx *ictx = crypto_instance_ctx(inst); + struct crypto_ccm_ctx *ctx = crypto_tfm_ctx(tfm); + struct crypto_cipher *cipher; + struct crypto_ablkcipher *ctr; + unsigned long align; + int err; + + cipher = crypto_spawn_cipher(&ictx->cipher); + if (IS_ERR(cipher)) + return PTR_ERR(cipher); + + ctr = crypto_spawn_skcipher(&ictx->ctr); + err = PTR_ERR(ctr); + if (IS_ERR(ctr)) + goto err_free_cipher; + + ctx->cipher = cipher; + ctx->ctr = ctr; + + align = crypto_tfm_alg_alignmask(tfm); + align &= ~(crypto_tfm_ctx_alignment() - 1); + tfm->crt_aead.reqsize = align + + sizeof(struct crypto_ccm_req_priv_ctx) + + crypto_ablkcipher_reqsize(ctr); + + return 0; + +err_free_cipher: + crypto_free_cipher(cipher); + return err; +} + +static void crypto_ccm_exit_tfm(struct crypto_tfm *tfm) +{ + struct crypto_ccm_ctx *ctx = crypto_tfm_ctx(tfm); + + crypto_free_cipher(ctx->cipher); + crypto_free_ablkcipher(ctx->ctr); +} + +static struct crypto_instance *crypto_ccm_alloc_common(struct rtattr **tb, + const char *full_name, + const char *ctr_name, + const char *cipher_name) +{ + struct crypto_attr_type *algt; + struct crypto_instance *inst; + struct crypto_alg *ctr; + struct crypto_alg *cipher; + struct ccm_instance_ctx *ictx; + int err; + + algt = crypto_get_attr_type(tb); + err = PTR_ERR(algt); + if (IS_ERR(algt)) + return ERR_PTR(err); + + if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask) + return ERR_PTR(-EINVAL); + + cipher = crypto_alg_mod_lookup(cipher_name, CRYPTO_ALG_TYPE_CIPHER, + CRYPTO_ALG_TYPE_MASK); + err = PTR_ERR(cipher); + if (IS_ERR(cipher)) + return ERR_PTR(err); + + err = -EINVAL; + if (cipher->cra_blocksize != 16) + goto out_put_cipher; + + inst = kzalloc(sizeof(*inst) + sizeof(*ictx), GFP_KERNEL); + err = -ENOMEM; + if (!inst) + goto out_put_cipher; + + ictx = crypto_instance_ctx(inst); + + err = crypto_init_spawn(&ictx->cipher, cipher, inst, + CRYPTO_ALG_TYPE_MASK); + if (err) + goto err_free_inst; + + crypto_set_skcipher_spawn(&ictx->ctr, inst); + err = crypto_grab_skcipher(&ictx->ctr, ctr_name, 0, + crypto_requires_sync(algt->type, + algt->mask)); + if (err) + goto err_drop_cipher; + + ctr = crypto_skcipher_spawn_alg(&ictx->ctr); + + /* Not a stream cipher? */ + err = -EINVAL; + if (ctr->cra_blocksize != 1) + goto err_drop_ctr; + + /* We want the real thing! */ + if (ctr->cra_ablkcipher.ivsize != 16) + goto err_drop_ctr; + + err = -ENAMETOOLONG; + if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, + "ccm_base(%s,%s)", ctr->cra_driver_name, + cipher->cra_driver_name) >= CRYPTO_MAX_ALG_NAME) + goto err_drop_ctr; + + memcpy(inst->alg.cra_name, full_name, CRYPTO_MAX_ALG_NAME); + + inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD; + inst->alg.cra_flags |= ctr->cra_flags & CRYPTO_ALG_ASYNC; + inst->alg.cra_priority = cipher->cra_priority + ctr->cra_priority; + inst->alg.cra_blocksize = 1; + inst->alg.cra_alignmask = cipher->cra_alignmask | ctr->cra_alignmask | + (__alignof__(u32) - 1); + inst->alg.cra_type = &crypto_aead_type; + inst->alg.cra_aead.ivsize = 16; + inst->alg.cra_aead.maxauthsize = 16; + inst->alg.cra_ctxsize = sizeof(struct crypto_ccm_ctx); + inst->alg.cra_init = crypto_ccm_init_tfm; + inst->alg.cra_exit = crypto_ccm_exit_tfm; + inst->alg.cra_aead.setkey = crypto_ccm_setkey; + inst->alg.cra_aead.setauthsize = crypto_ccm_setauthsize; + inst->alg.cra_aead.encrypt = crypto_ccm_encrypt; + inst->alg.cra_aead.decrypt = crypto_ccm_decrypt; + +out: + crypto_mod_put(cipher); + return inst; + +err_drop_ctr: + crypto_drop_skcipher(&ictx->ctr); +err_drop_cipher: + crypto_drop_spawn(&ictx->cipher); +err_free_inst: + kfree(inst); +out_put_cipher: + inst = ERR_PTR(err); + goto out; +} + +static struct crypto_instance *crypto_ccm_alloc(struct rtattr **tb) +{ + int err; + const char *cipher_name; + char ctr_name[CRYPTO_MAX_ALG_NAME]; + char full_name[CRYPTO_MAX_ALG_NAME]; + + cipher_name = crypto_attr_alg_name(tb[1]); + err = PTR_ERR(cipher_name); + if (IS_ERR(cipher_name)) + return ERR_PTR(err); + + if (snprintf(ctr_name, CRYPTO_MAX_ALG_NAME, "ctr(%s)", + cipher_name) >= CRYPTO_MAX_ALG_NAME) + return ERR_PTR(-ENAMETOOLONG); + + if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "ccm(%s)", cipher_name) >= + CRYPTO_MAX_ALG_NAME) + return ERR_PTR(-ENAMETOOLONG); + + return crypto_ccm_alloc_common(tb, full_name, ctr_name, cipher_name); +} + +static void crypto_ccm_free(struct crypto_instance *inst) +{ + struct ccm_instance_ctx *ctx = crypto_instance_ctx(inst); + + crypto_drop_spawn(&ctx->cipher); + crypto_drop_skcipher(&ctx->ctr); + kfree(inst); +} + +static struct crypto_template crypto_ccm_tmpl = { + .name = "ccm", + .alloc = crypto_ccm_alloc, + .free = crypto_ccm_free, + .module = THIS_MODULE, +}; + +static struct crypto_instance *crypto_ccm_base_alloc(struct rtattr **tb) +{ + int err; + const char *ctr_name; + const char *cipher_name; + char full_name[CRYPTO_MAX_ALG_NAME]; + + ctr_name = crypto_attr_alg_name(tb[1]); + err = PTR_ERR(ctr_name); + if (IS_ERR(ctr_name)) + return ERR_PTR(err); + + cipher_name = crypto_attr_alg_name(tb[2]); + err = PTR_ERR(cipher_name); + if (IS_ERR(cipher_name)) + return ERR_PTR(err); + + if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "ccm_base(%s,%s)", + ctr_name, cipher_name) >= CRYPTO_MAX_ALG_NAME) + return ERR_PTR(-ENAMETOOLONG); + + return crypto_ccm_alloc_common(tb, full_name, ctr_name, cipher_name); +} + +static struct crypto_template crypto_ccm_base_tmpl = { + .name = "ccm_base", + .alloc = crypto_ccm_base_alloc, + .free = crypto_ccm_free, + .module = THIS_MODULE, +}; + +static int crypto_rfc4309_setkey(struct crypto_aead *parent, const u8 *key, + unsigned int keylen) +{ + struct crypto_rfc4309_ctx *ctx = crypto_aead_ctx(parent); + struct crypto_aead *child = ctx->child; + int err; + + if (keylen < 3) + return -EINVAL; + + keylen -= 3; + memcpy(ctx->nonce, key + keylen, 3); + + crypto_aead_clear_flags(child, CRYPTO_TFM_REQ_MASK); + crypto_aead_set_flags(child, crypto_aead_get_flags(parent) & + CRYPTO_TFM_REQ_MASK); + err = crypto_aead_setkey(child, key, keylen); + crypto_aead_set_flags(parent, crypto_aead_get_flags(child) & + CRYPTO_TFM_RES_MASK); + + return err; +} + +static int crypto_rfc4309_setauthsize(struct crypto_aead *parent, + unsigned int authsize) +{ + struct crypto_rfc4309_ctx *ctx = crypto_aead_ctx(parent); + + switch (authsize) { + case 8: + case 12: + case 16: + break; + default: + return -EINVAL; + } + + return crypto_aead_setauthsize(ctx->child, authsize); +} + +static struct aead_request *crypto_rfc4309_crypt(struct aead_request *req) +{ + struct aead_request *subreq = aead_request_ctx(req); + struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct crypto_rfc4309_ctx *ctx = crypto_aead_ctx(aead); + struct crypto_aead *child = ctx->child; + u8 *iv = PTR_ALIGN((u8 *)(subreq + 1) + crypto_aead_reqsize(child), + crypto_aead_alignmask(child) + 1); + + /* L' */ + iv[0] = 3; + + memcpy(iv + 1, ctx->nonce, 3); + memcpy(iv + 4, req->iv, 8); + + aead_request_set_tfm(subreq, child); + aead_request_set_callback(subreq, req->base.flags, req->base.complete, + req->base.data); + aead_request_set_crypt(subreq, req->src, req->dst, req->cryptlen, iv); + aead_request_set_assoc(subreq, req->assoc, req->assoclen); + + return subreq; +} + +static int crypto_rfc4309_encrypt(struct aead_request *req) +{ + req = crypto_rfc4309_crypt(req); + + return crypto_aead_encrypt(req); +} + +static int crypto_rfc4309_decrypt(struct aead_request *req) +{ + req = crypto_rfc4309_crypt(req); + + return crypto_aead_decrypt(req); +} + +static int crypto_rfc4309_init_tfm(struct crypto_tfm *tfm) +{ + struct crypto_instance *inst = (void *)tfm->__crt_alg; + struct crypto_aead_spawn *spawn = crypto_instance_ctx(inst); + struct crypto_rfc4309_ctx *ctx = crypto_tfm_ctx(tfm); + struct crypto_aead *aead; + unsigned long align; + + aead = crypto_spawn_aead(spawn); + if (IS_ERR(aead)) + return PTR_ERR(aead); + + ctx->child = aead; + + align = crypto_aead_alignmask(aead); + align &= ~(crypto_tfm_ctx_alignment() - 1); + tfm->crt_aead.reqsize = sizeof(struct aead_request) + + ALIGN(crypto_aead_reqsize(aead), + crypto_tfm_ctx_alignment()) + + align + 16; + + return 0; +} + +static void crypto_rfc4309_exit_tfm(struct crypto_tfm *tfm) +{ + struct crypto_rfc4309_ctx *ctx = crypto_tfm_ctx(tfm); + + crypto_free_aead(ctx->child); +} + +static struct crypto_instance *crypto_rfc4309_alloc(struct rtattr **tb) +{ + struct crypto_attr_type *algt; + struct crypto_instance *inst; + struct crypto_aead_spawn *spawn; + struct crypto_alg *alg; + const char *ccm_name; + int err; + + algt = crypto_get_attr_type(tb); + err = PTR_ERR(algt); + if (IS_ERR(algt)) + return ERR_PTR(err); + + if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask) + return ERR_PTR(-EINVAL); + + ccm_name = crypto_attr_alg_name(tb[1]); + err = PTR_ERR(ccm_name); + if (IS_ERR(ccm_name)) + return ERR_PTR(err); + + inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL); + if (!inst) + return ERR_PTR(-ENOMEM); + + spawn = crypto_instance_ctx(inst); + crypto_set_aead_spawn(spawn, inst); + err = crypto_grab_aead(spawn, ccm_name, 0, + crypto_requires_sync(algt->type, algt->mask)); + if (err) + goto out_free_inst; + + alg = crypto_aead_spawn_alg(spawn); + + err = -EINVAL; + + /* We only support 16-byte blocks. */ + if (alg->cra_aead.ivsize != 16) + goto out_drop_alg; + + /* Not a stream cipher? */ + if (alg->cra_blocksize != 1) + goto out_drop_alg; + + err = -ENAMETOOLONG; + if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, + "rfc4309(%s)", alg->cra_name) >= CRYPTO_MAX_ALG_NAME || + snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, + "rfc4309(%s)", alg->cra_driver_name) >= + CRYPTO_MAX_ALG_NAME) + goto out_drop_alg; + + inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD; + inst->alg.cra_flags |= alg->cra_flags & CRYPTO_ALG_ASYNC; + inst->alg.cra_priority = alg->cra_priority; + inst->alg.cra_blocksize = 1; + inst->alg.cra_alignmask = alg->cra_alignmask; + inst->alg.cra_type = &crypto_nivaead_type; + + inst->alg.cra_aead.ivsize = 8; + inst->alg.cra_aead.maxauthsize = 16; + + inst->alg.cra_ctxsize = sizeof(struct crypto_rfc4309_ctx); + + inst->alg.cra_init = crypto_rfc4309_init_tfm; + inst->alg.cra_exit = crypto_rfc4309_exit_tfm; + + inst->alg.cra_aead.setkey = crypto_rfc4309_setkey; + inst->alg.cra_aead.setauthsize = crypto_rfc4309_setauthsize; + inst->alg.cra_aead.encrypt = crypto_rfc4309_encrypt; + inst->alg.cra_aead.decrypt = crypto_rfc4309_decrypt; + + inst->alg.cra_aead.geniv = "seqiv"; + +out: + return inst; + +out_drop_alg: + crypto_drop_aead(spawn); +out_free_inst: + kfree(inst); + inst = ERR_PTR(err); + goto out; +} + +static void crypto_rfc4309_free(struct crypto_instance *inst) +{ + crypto_drop_spawn(crypto_instance_ctx(inst)); + kfree(inst); +} + +static struct crypto_template crypto_rfc4309_tmpl = { + .name = "rfc4309", + .alloc = crypto_rfc4309_alloc, + .free = crypto_rfc4309_free, + .module = THIS_MODULE, +}; + +static int __init crypto_ccm_module_init(void) +{ + int err; + + err = crypto_register_template(&crypto_ccm_base_tmpl); + if (err) + goto out; + + err = crypto_register_template(&crypto_ccm_tmpl); + if (err) + goto out_undo_base; + + err = crypto_register_template(&crypto_rfc4309_tmpl); + if (err) + goto out_undo_ccm; + +out: + return err; + +out_undo_ccm: + crypto_unregister_template(&crypto_ccm_tmpl); +out_undo_base: + crypto_unregister_template(&crypto_ccm_base_tmpl); + goto out; +} + +static void __exit crypto_ccm_module_exit(void) +{ + crypto_unregister_template(&crypto_rfc4309_tmpl); + crypto_unregister_template(&crypto_ccm_tmpl); + crypto_unregister_template(&crypto_ccm_base_tmpl); +} + +module_init(crypto_ccm_module_init); +module_exit(crypto_ccm_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Counter with CBC MAC"); +MODULE_ALIAS("ccm_base"); +MODULE_ALIAS("rfc4309"); diff --git a/crypto/chainiv.c b/crypto/chainiv.c new file mode 100644 index 000000000000..d17fa0454dc3 --- /dev/null +++ b/crypto/chainiv.c @@ -0,0 +1,331 @@ +/* + * chainiv: Chain IV Generator + * + * Generate IVs simply be using the last block of the previous encryption. + * This is mainly useful for CBC with a synchronous algorithm. + * + * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au> + * + * 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. + * + */ + +#include <crypto/internal/skcipher.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/random.h> +#include <linux/spinlock.h> +#include <linux/string.h> +#include <linux/workqueue.h> + +enum { + CHAINIV_STATE_INUSE = 0, +}; + +struct chainiv_ctx { + spinlock_t lock; + char iv[]; +}; + +struct async_chainiv_ctx { + unsigned long state; + + spinlock_t lock; + int err; + + struct crypto_queue queue; + struct work_struct postponed; + + char iv[]; +}; + +static int chainiv_givencrypt(struct skcipher_givcrypt_request *req) +{ + struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req); + struct chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv); + struct ablkcipher_request *subreq = skcipher_givcrypt_reqctx(req); + unsigned int ivsize; + int err; + + ablkcipher_request_set_tfm(subreq, skcipher_geniv_cipher(geniv)); + ablkcipher_request_set_callback(subreq, req->creq.base.flags & + ~CRYPTO_TFM_REQ_MAY_SLEEP, + req->creq.base.complete, + req->creq.base.data); + ablkcipher_request_set_crypt(subreq, req->creq.src, req->creq.dst, + req->creq.nbytes, req->creq.info); + + spin_lock_bh(&ctx->lock); + + ivsize = crypto_ablkcipher_ivsize(geniv); + + memcpy(req->giv, ctx->iv, ivsize); + memcpy(subreq->info, ctx->iv, ivsize); + + err = crypto_ablkcipher_encrypt(subreq); + if (err) + goto unlock; + + memcpy(ctx->iv, subreq->info, ivsize); + +unlock: + spin_unlock_bh(&ctx->lock); + + return err; +} + +static int chainiv_givencrypt_first(struct skcipher_givcrypt_request *req) +{ + struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req); + struct chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv); + + spin_lock_bh(&ctx->lock); + if (crypto_ablkcipher_crt(geniv)->givencrypt != + chainiv_givencrypt_first) + goto unlock; + + crypto_ablkcipher_crt(geniv)->givencrypt = chainiv_givencrypt; + get_random_bytes(ctx->iv, crypto_ablkcipher_ivsize(geniv)); + +unlock: + spin_unlock_bh(&ctx->lock); + + return chainiv_givencrypt(req); +} + +static int chainiv_init_common(struct crypto_tfm *tfm) +{ + tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request); + + return skcipher_geniv_init(tfm); +} + +static int chainiv_init(struct crypto_tfm *tfm) +{ + struct chainiv_ctx *ctx = crypto_tfm_ctx(tfm); + + spin_lock_init(&ctx->lock); + + return chainiv_init_common(tfm); +} + +static int async_chainiv_schedule_work(struct async_chainiv_ctx *ctx) +{ + int queued; + + if (!ctx->queue.qlen) { + smp_mb__before_clear_bit(); + clear_bit(CHAINIV_STATE_INUSE, &ctx->state); + + if (!ctx->queue.qlen || + test_and_set_bit(CHAINIV_STATE_INUSE, &ctx->state)) + goto out; + } + + queued = schedule_work(&ctx->postponed); + BUG_ON(!queued); + +out: + return ctx->err; +} + +static int async_chainiv_postpone_request(struct skcipher_givcrypt_request *req) +{ + struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req); + struct async_chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv); + int err; + + spin_lock_bh(&ctx->lock); + err = skcipher_enqueue_givcrypt(&ctx->queue, req); + spin_unlock_bh(&ctx->lock); + + if (test_and_set_bit(CHAINIV_STATE_INUSE, &ctx->state)) + return err; + + ctx->err = err; + return async_chainiv_schedule_work(ctx); +} + +static int async_chainiv_givencrypt_tail(struct skcipher_givcrypt_request *req) +{ + struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req); + struct async_chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv); + struct ablkcipher_request *subreq = skcipher_givcrypt_reqctx(req); + unsigned int ivsize = crypto_ablkcipher_ivsize(geniv); + + memcpy(req->giv, ctx->iv, ivsize); + memcpy(subreq->info, ctx->iv, ivsize); + + ctx->err = crypto_ablkcipher_encrypt(subreq); + if (ctx->err) + goto out; + + memcpy(ctx->iv, subreq->info, ivsize); + +out: + return async_chainiv_schedule_work(ctx); +} + +static int async_chainiv_givencrypt(struct skcipher_givcrypt_request *req) +{ + struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req); + struct async_chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv); + struct ablkcipher_request *subreq = skcipher_givcrypt_reqctx(req); + + ablkcipher_request_set_tfm(subreq, skcipher_geniv_cipher(geniv)); + ablkcipher_request_set_callback(subreq, req->creq.base.flags, + req->creq.base.complete, + req->creq.base.data); + ablkcipher_request_set_crypt(subreq, req->creq.src, req->creq.dst, + req->creq.nbytes, req->creq.info); + + if (test_and_set_bit(CHAINIV_STATE_INUSE, &ctx->state)) + goto postpone; + + if (ctx->queue.qlen) { + clear_bit(CHAINIV_STATE_INUSE, &ctx->state); + goto postpone; + } + + return async_chainiv_givencrypt_tail(req); + +postpone: + return async_chainiv_postpone_request(req); +} + +static int async_chainiv_givencrypt_first(struct skcipher_givcrypt_request *req) +{ + struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req); + struct async_chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv); + + if (test_and_set_bit(CHAINIV_STATE_INUSE, &ctx->state)) + goto out; + + if (crypto_ablkcipher_crt(geniv)->givencrypt != + async_chainiv_givencrypt_first) + goto unlock; + + crypto_ablkcipher_crt(geniv)->givencrypt = async_chainiv_givencrypt; + get_random_bytes(ctx->iv, crypto_ablkcipher_ivsize(geniv)); + +unlock: + clear_bit(CHAINIV_STATE_INUSE, &ctx->state); + +out: + return async_chainiv_givencrypt(req); +} + +static void async_chainiv_do_postponed(struct work_struct *work) +{ + struct async_chainiv_ctx *ctx = container_of(work, + struct async_chainiv_ctx, + postponed); + struct skcipher_givcrypt_request *req; + struct ablkcipher_request *subreq; + + /* Only handle one request at a time to avoid hogging keventd. */ + spin_lock_bh(&ctx->lock); + req = skcipher_dequeue_givcrypt(&ctx->queue); + spin_unlock_bh(&ctx->lock); + + if (!req) { + async_chainiv_schedule_work(ctx); + return; + } + + subreq = skcipher_givcrypt_reqctx(req); + subreq->base.flags |= CRYPTO_TFM_REQ_MAY_SLEEP; + + async_chainiv_givencrypt_tail(req); +} + +static int async_chainiv_init(struct crypto_tfm *tfm) +{ + struct async_chainiv_ctx *ctx = crypto_tfm_ctx(tfm); + + spin_lock_init(&ctx->lock); + + crypto_init_queue(&ctx->queue, 100); + INIT_WORK(&ctx->postponed, async_chainiv_do_postponed); + + return chainiv_init_common(tfm); +} + +static void async_chainiv_exit(struct crypto_tfm *tfm) +{ + struct async_chainiv_ctx *ctx = crypto_tfm_ctx(tfm); + + BUG_ON(test_bit(CHAINIV_STATE_INUSE, &ctx->state) || ctx->queue.qlen); + + skcipher_geniv_exit(tfm); +} + +static struct crypto_template chainiv_tmpl; + +static struct crypto_instance *chainiv_alloc(struct rtattr **tb) +{ + struct crypto_attr_type *algt; + struct crypto_instance *inst; + int err; + + algt = crypto_get_attr_type(tb); + err = PTR_ERR(algt); + if (IS_ERR(algt)) + return ERR_PTR(err); + + inst = skcipher_geniv_alloc(&chainiv_tmpl, tb, 0, 0); + if (IS_ERR(inst)) + goto out; + + inst->alg.cra_ablkcipher.givencrypt = chainiv_givencrypt_first; + + inst->alg.cra_init = chainiv_init; + inst->alg.cra_exit = skcipher_geniv_exit; + + inst->alg.cra_ctxsize = sizeof(struct chainiv_ctx); + + if (!crypto_requires_sync(algt->type, algt->mask)) { + inst->alg.cra_flags |= CRYPTO_ALG_ASYNC; + + inst->alg.cra_ablkcipher.givencrypt = + async_chainiv_givencrypt_first; + + inst->alg.cra_init = async_chainiv_init; + inst->alg.cra_exit = async_chainiv_exit; + + inst->alg.cra_ctxsize = sizeof(struct async_chainiv_ctx); + } + + inst->alg.cra_ctxsize += inst->alg.cra_ablkcipher.ivsize; + +out: + return inst; +} + +static struct crypto_template chainiv_tmpl = { + .name = "chainiv", + .alloc = chainiv_alloc, + .free = skcipher_geniv_free, + .module = THIS_MODULE, +}; + +static int __init chainiv_module_init(void) +{ + return crypto_register_template(&chainiv_tmpl); +} + +static void __exit chainiv_module_exit(void) +{ + crypto_unregister_template(&chainiv_tmpl); +} + +module_init(chainiv_module_init); +module_exit(chainiv_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Chain IV Generator"); diff --git a/crypto/cryptd.c b/crypto/cryptd.c index 8bf2da835f7b..074298f2f8e3 100644 --- a/crypto/cryptd.c +++ b/crypto/cryptd.c @@ -228,7 +228,7 @@ static struct crypto_instance *cryptd_alloc_blkcipher( struct crypto_alg *alg; alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_BLKCIPHER, - CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); + CRYPTO_ALG_TYPE_MASK); if (IS_ERR(alg)) return ERR_PTR(PTR_ERR(alg)); @@ -236,13 +236,15 @@ static struct crypto_instance *cryptd_alloc_blkcipher( if (IS_ERR(inst)) goto out_put_alg; - inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_ASYNC; + inst->alg.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC; inst->alg.cra_type = &crypto_ablkcipher_type; inst->alg.cra_ablkcipher.ivsize = alg->cra_blkcipher.ivsize; inst->alg.cra_ablkcipher.min_keysize = alg->cra_blkcipher.min_keysize; inst->alg.cra_ablkcipher.max_keysize = alg->cra_blkcipher.max_keysize; + inst->alg.cra_ablkcipher.geniv = alg->cra_blkcipher.geniv; + inst->alg.cra_ctxsize = sizeof(struct cryptd_blkcipher_ctx); inst->alg.cra_init = cryptd_blkcipher_init_tfm; diff --git a/crypto/crypto_null.c b/crypto/crypto_null.c index 29f77477d701..ff7b3de1bcfd 100644 --- a/crypto/crypto_null.c +++ b/crypto/crypto_null.c @@ -16,15 +16,17 @@ * (at your option) any later version. * */ + +#include <crypto/internal/skcipher.h> #include <linux/init.h> #include <linux/module.h> #include <linux/mm.h> -#include <linux/crypto.h> #include <linux/string.h> #define NULL_KEY_SIZE 0 #define NULL_BLOCK_SIZE 1 #define NULL_DIGEST_SIZE 0 +#define NULL_IV_SIZE 0 static int null_compress(struct crypto_tfm *tfm, const u8 *src, unsigned int slen, u8 *dst, unsigned int *dlen) @@ -55,6 +57,26 @@ static void null_crypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) memcpy(dst, src, NULL_BLOCK_SIZE); } +static int skcipher_null_crypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct blkcipher_walk walk; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + while (walk.nbytes) { + if (walk.src.virt.addr != walk.dst.virt.addr) + memcpy(walk.dst.virt.addr, walk.src.virt.addr, + walk.nbytes); + err = blkcipher_walk_done(desc, &walk, 0); + } + + return err; +} + static struct crypto_alg compress_null = { .cra_name = "compress_null", .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, @@ -76,6 +98,7 @@ static struct crypto_alg digest_null = { .cra_list = LIST_HEAD_INIT(digest_null.cra_list), .cra_u = { .digest = { .dia_digestsize = NULL_DIGEST_SIZE, + .dia_setkey = null_setkey, .dia_init = null_init, .dia_update = null_update, .dia_final = null_final } } @@ -96,6 +119,25 @@ static struct crypto_alg cipher_null = { .cia_decrypt = null_crypt } } }; +static struct crypto_alg skcipher_null = { + .cra_name = "ecb(cipher_null)", + .cra_driver_name = "ecb-cipher_null", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = NULL_BLOCK_SIZE, + .cra_type = &crypto_blkcipher_type, + .cra_ctxsize = 0, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(skcipher_null.cra_list), + .cra_u = { .blkcipher = { + .min_keysize = NULL_KEY_SIZE, + .max_keysize = NULL_KEY_SIZE, + .ivsize = NULL_IV_SIZE, + .setkey = null_setkey, + .encrypt = skcipher_null_crypt, + .decrypt = skcipher_null_crypt } } +}; + MODULE_ALIAS("compress_null"); MODULE_ALIAS("digest_null"); MODULE_ALIAS("cipher_null"); @@ -108,27 +150,35 @@ static int __init init(void) if (ret < 0) goto out; + ret = crypto_register_alg(&skcipher_null); + if (ret < 0) + goto out_unregister_cipher; + ret = crypto_register_alg(&digest_null); - if (ret < 0) { - crypto_unregister_alg(&cipher_null); - goto out; - } + if (ret < 0) + goto out_unregister_skcipher; ret = crypto_register_alg(&compress_null); - if (ret < 0) { - crypto_unregister_alg(&digest_null); - crypto_unregister_alg(&cipher_null); - goto out; - } + if (ret < 0) + goto out_unregister_digest; out: return ret; + +out_unregister_digest: + crypto_unregister_alg(&digest_null); +out_unregister_skcipher: + crypto_unregister_alg(&skcipher_null); +out_unregister_cipher: + crypto_unregister_alg(&cipher_null); + goto out; } static void __exit fini(void) { crypto_unregister_alg(&compress_null); crypto_unregister_alg(&digest_null); + crypto_unregister_alg(&skcipher_null); crypto_unregister_alg(&cipher_null); } diff --git a/crypto/ctr.c b/crypto/ctr.c new file mode 100644 index 000000000000..2d7425f0e7b8 --- /dev/null +++ b/crypto/ctr.c @@ -0,0 +1,422 @@ +/* + * CTR: Counter mode + * + * (C) Copyright IBM Corp. 2007 - Joy Latten <latten@us.ibm.com> + * + * 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. + * + */ + +#include <crypto/algapi.h> +#include <crypto/ctr.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/random.h> +#include <linux/scatterlist.h> +#include <linux/slab.h> + +struct crypto_ctr_ctx { + struct crypto_cipher *child; +}; + +struct crypto_rfc3686_ctx { + struct crypto_blkcipher *child; + u8 nonce[CTR_RFC3686_NONCE_SIZE]; +}; + +static int crypto_ctr_setkey(struct crypto_tfm *parent, const u8 *key, + unsigned int keylen) +{ + struct crypto_ctr_ctx *ctx = crypto_tfm_ctx(parent); + struct crypto_cipher *child = ctx->child; + int err; + + crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); + crypto_cipher_set_flags(child, crypto_tfm_get_flags(parent) & + CRYPTO_TFM_REQ_MASK); + err = crypto_cipher_setkey(child, key, keylen); + crypto_tfm_set_flags(parent, crypto_cipher_get_flags(child) & + CRYPTO_TFM_RES_MASK); + + return err; +} + +static void crypto_ctr_crypt_final(struct blkcipher_walk *walk, + struct crypto_cipher *tfm) +{ + unsigned int bsize = crypto_cipher_blocksize(tfm); + unsigned long alignmask = crypto_cipher_alignmask(tfm); + u8 *ctrblk = walk->iv; + u8 tmp[bsize + alignmask]; + u8 *keystream = PTR_ALIGN(tmp + 0, alignmask + 1); + u8 *src = walk->src.virt.addr; + u8 *dst = walk->dst.virt.addr; + unsigned int nbytes = walk->nbytes; + + crypto_cipher_encrypt_one(tfm, keystream, ctrblk); + crypto_xor(keystream, src, nbytes); + memcpy(dst, keystream, nbytes); + + crypto_inc(ctrblk, bsize); +} + +static int crypto_ctr_crypt_segment(struct blkcipher_walk *walk, + struct crypto_cipher *tfm) +{ + void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = + crypto_cipher_alg(tfm)->cia_encrypt; + unsigned int bsize = crypto_cipher_blocksize(tfm); + u8 *ctrblk = walk->iv; + u8 *src = walk->src.virt.addr; + u8 *dst = walk->dst.virt.addr; + unsigned int nbytes = walk->nbytes; + + do { + /* create keystream */ + fn(crypto_cipher_tfm(tfm), dst, ctrblk); + crypto_xor(dst, src, bsize); + + /* increment counter in counterblock */ + crypto_inc(ctrblk, bsize); + + src += bsize; + dst += bsize; + } while ((nbytes -= bsize) >= bsize); + + return nbytes; +} + +static int crypto_ctr_crypt_inplace(struct blkcipher_walk *walk, + struct crypto_cipher *tfm) +{ + void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = + crypto_cipher_alg(tfm)->cia_encrypt; + unsigned int bsize = crypto_cipher_blocksize(tfm); + unsigned long alignmask = crypto_cipher_alignmask(tfm); + unsigned int nbytes = walk->nbytes; + u8 *ctrblk = walk->iv; + u8 *src = walk->src.virt.addr; + u8 tmp[bsize + alignmask]; + u8 *keystream = PTR_ALIGN(tmp + 0, alignmask + 1); + + do { + /* create keystream */ + fn(crypto_cipher_tfm(tfm), keystream, ctrblk); + crypto_xor(src, keystream, bsize); + + /* increment counter in counterblock */ + crypto_inc(ctrblk, bsize); + + src += bsize; + } while ((nbytes -= bsize) >= bsize); + + return nbytes; +} + +static int crypto_ctr_crypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct blkcipher_walk walk; + struct crypto_blkcipher *tfm = desc->tfm; + struct crypto_ctr_ctx *ctx = crypto_blkcipher_ctx(tfm); + struct crypto_cipher *child = ctx->child; + unsigned int bsize = crypto_cipher_blocksize(child); + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt_block(desc, &walk, bsize); + + while (walk.nbytes >= bsize) { + if (walk.src.virt.addr == walk.dst.virt.addr) + nbytes = crypto_ctr_crypt_inplace(&walk, child); + else + nbytes = crypto_ctr_crypt_segment(&walk, child); + + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + if (walk.nbytes) { + crypto_ctr_crypt_final(&walk, child); + err = blkcipher_walk_done(desc, &walk, 0); + } + + return err; +} + +static int crypto_ctr_init_tfm(struct crypto_tfm *tfm) +{ + struct crypto_instance *inst = (void *)tfm->__crt_alg; + struct crypto_spawn *spawn = crypto_instance_ctx(inst); + struct crypto_ctr_ctx *ctx = crypto_tfm_ctx(tfm); + struct crypto_cipher *cipher; + + cipher = crypto_spawn_cipher(spawn); + if (IS_ERR(cipher)) + return PTR_ERR(cipher); + + ctx->child = cipher; + + return 0; +} + +static void crypto_ctr_exit_tfm(struct crypto_tfm *tfm) +{ + struct crypto_ctr_ctx *ctx = crypto_tfm_ctx(tfm); + + crypto_free_cipher(ctx->child); +} + +static struct crypto_instance *crypto_ctr_alloc(struct rtattr **tb) +{ + struct crypto_instance *inst; + struct crypto_alg *alg; + int err; + + err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER); + if (err) + return ERR_PTR(err); + + alg = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_CIPHER, + CRYPTO_ALG_TYPE_MASK); + if (IS_ERR(alg)) + return ERR_PTR(PTR_ERR(alg)); + + /* Block size must be >= 4 bytes. */ + err = -EINVAL; + if (alg->cra_blocksize < 4) + goto out_put_alg; + + /* If this is false we'd fail the alignment of crypto_inc. */ + if (alg->cra_blocksize % 4) + goto out_put_alg; + + inst = crypto_alloc_instance("ctr", alg); + if (IS_ERR(inst)) + goto out; + + inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER; + inst->alg.cra_priority = alg->cra_priority; + inst->alg.cra_blocksize = 1; + inst->alg.cra_alignmask = alg->cra_alignmask | (__alignof__(u32) - 1); + inst->alg.cra_type = &crypto_blkcipher_type; + + inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize; + inst->alg.cra_blkcipher.min_keysize = alg->cra_cipher.cia_min_keysize; + inst->alg.cra_blkcipher.max_keysize = alg->cra_cipher.cia_max_keysize; + + inst->alg.cra_ctxsize = sizeof(struct crypto_ctr_ctx); + + inst->alg.cra_init = crypto_ctr_init_tfm; + inst->alg.cra_exit = crypto_ctr_exit_tfm; + + inst->alg.cra_blkcipher.setkey = crypto_ctr_setkey; + inst->alg.cra_blkcipher.encrypt = crypto_ctr_crypt; + inst->alg.cra_blkcipher.decrypt = crypto_ctr_crypt; + +out: + crypto_mod_put(alg); + return inst; + +out_put_alg: + inst = ERR_PTR(err); + goto out; +} + +static void crypto_ctr_free(struct crypto_instance *inst) +{ + crypto_drop_spawn(crypto_instance_ctx(inst)); + kfree(inst); +} + +static struct crypto_template crypto_ctr_tmpl = { + .name = "ctr", + .alloc = crypto_ctr_alloc, + .free = crypto_ctr_free, + .module = THIS_MODULE, +}; + +static int crypto_rfc3686_setkey(struct crypto_tfm *parent, const u8 *key, + unsigned int keylen) +{ + struct crypto_rfc3686_ctx *ctx = crypto_tfm_ctx(parent); + struct crypto_blkcipher *child = ctx->child; + int err; + + /* the nonce is stored in bytes at end of key */ + if (keylen < CTR_RFC3686_NONCE_SIZE) + return -EINVAL; + + memcpy(ctx->nonce, key + (keylen - CTR_RFC3686_NONCE_SIZE), + CTR_RFC3686_NONCE_SIZE); + + keylen -= CTR_RFC3686_NONCE_SIZE; + + crypto_blkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); + crypto_blkcipher_set_flags(child, crypto_tfm_get_flags(parent) & + CRYPTO_TFM_REQ_MASK); + err = crypto_blkcipher_setkey(child, key, keylen); + crypto_tfm_set_flags(parent, crypto_blkcipher_get_flags(child) & + CRYPTO_TFM_RES_MASK); + + return err; +} + +static int crypto_rfc3686_crypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct crypto_blkcipher *tfm = desc->tfm; + struct crypto_rfc3686_ctx *ctx = crypto_blkcipher_ctx(tfm); + struct crypto_blkcipher *child = ctx->child; + unsigned long alignmask = crypto_blkcipher_alignmask(tfm); + u8 ivblk[CTR_RFC3686_BLOCK_SIZE + alignmask]; + u8 *iv = PTR_ALIGN(ivblk + 0, alignmask + 1); + u8 *info = desc->info; + int err; + + /* set up counter block */ + memcpy(iv, ctx->nonce, CTR_RFC3686_NONCE_SIZE); + memcpy(iv + CTR_RFC3686_NONCE_SIZE, info, CTR_RFC3686_IV_SIZE); + + /* initialize counter portion of counter block */ + *(__be32 *)(iv + CTR_RFC3686_NONCE_SIZE + CTR_RFC3686_IV_SIZE) = + cpu_to_be32(1); + + desc->tfm = child; + desc->info = iv; + err = crypto_blkcipher_encrypt_iv(desc, dst, src, nbytes); + desc->tfm = tfm; + desc->info = info; + + return err; +} + +static int crypto_rfc3686_init_tfm(struct crypto_tfm *tfm) +{ + struct crypto_instance *inst = (void *)tfm->__crt_alg; + struct crypto_spawn *spawn = crypto_instance_ctx(inst); + struct crypto_rfc3686_ctx *ctx = crypto_tfm_ctx(tfm); + struct crypto_blkcipher *cipher; + + cipher = crypto_spawn_blkcipher(spawn); + if (IS_ERR(cipher)) + return PTR_ERR(cipher); + + ctx->child = cipher; + + return 0; +} + +static void crypto_rfc3686_exit_tfm(struct crypto_tfm *tfm) +{ + struct crypto_rfc3686_ctx *ctx = crypto_tfm_ctx(tfm); + + crypto_free_blkcipher(ctx->child); +} + +static struct crypto_instance *crypto_rfc3686_alloc(struct rtattr **tb) +{ + struct crypto_instance *inst; + struct crypto_alg *alg; + int err; + + err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER); + if (err) + return ERR_PTR(err); + + alg = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_BLKCIPHER, + CRYPTO_ALG_TYPE_MASK); + err = PTR_ERR(alg); + if (IS_ERR(alg)) + return ERR_PTR(err); + + /* We only support 16-byte blocks. */ + err = -EINVAL; + if (alg->cra_blkcipher.ivsize != CTR_RFC3686_BLOCK_SIZE) + goto out_put_alg; + + /* Not a stream cipher? */ + if (alg->cra_blocksize != 1) + goto out_put_alg; + + inst = crypto_alloc_instance("rfc3686", alg); + if (IS_ERR(inst)) + goto out; + + inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER; + inst->alg.cra_priority = alg->cra_priority; + inst->alg.cra_blocksize = 1; + inst->alg.cra_alignmask = alg->cra_alignmask; + inst->alg.cra_type = &crypto_blkcipher_type; + + inst->alg.cra_blkcipher.ivsize = CTR_RFC3686_IV_SIZE; + inst->alg.cra_blkcipher.min_keysize = alg->cra_blkcipher.min_keysize + + CTR_RFC3686_NONCE_SIZE; + inst->alg.cra_blkcipher.max_keysize = alg->cra_blkcipher.max_keysize + + CTR_RFC3686_NONCE_SIZE; + + inst->alg.cra_blkcipher.geniv = "seqiv"; + + inst->alg.cra_ctxsize = sizeof(struct crypto_rfc3686_ctx); + + inst->alg.cra_init = crypto_rfc3686_init_tfm; + inst->alg.cra_exit = crypto_rfc3686_exit_tfm; + + inst->alg.cra_blkcipher.setkey = crypto_rfc3686_setkey; + inst->alg.cra_blkcipher.encrypt = crypto_rfc3686_crypt; + inst->alg.cra_blkcipher.decrypt = crypto_rfc3686_crypt; + +out: + crypto_mod_put(alg); + return inst; + +out_put_alg: + inst = ERR_PTR(err); + goto out; +} + +static struct crypto_template crypto_rfc3686_tmpl = { + .name = "rfc3686", + .alloc = crypto_rfc3686_alloc, + .free = crypto_ctr_free, + .module = THIS_MODULE, +}; + +static int __init crypto_ctr_module_init(void) +{ + int err; + + err = crypto_register_template(&crypto_ctr_tmpl); + if (err) + goto out; + + err = crypto_register_template(&crypto_rfc3686_tmpl); + if (err) + goto out_drop_ctr; + +out: + return err; + +out_drop_ctr: + crypto_unregister_template(&crypto_ctr_tmpl); + goto out; +} + +static void __exit crypto_ctr_module_exit(void) +{ + crypto_unregister_template(&crypto_rfc3686_tmpl); + crypto_unregister_template(&crypto_ctr_tmpl); +} + +module_init(crypto_ctr_module_init); +module_exit(crypto_ctr_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("CTR Counter block mode"); +MODULE_ALIAS("rfc3686"); diff --git a/crypto/des_generic.c b/crypto/des_generic.c index 59966d14b8e0..355ecb71cb0d 100644 --- a/crypto/des_generic.c +++ b/crypto/des_generic.c @@ -20,13 +20,7 @@ #include <linux/crypto.h> #include <linux/types.h> -#define DES_KEY_SIZE 8 -#define DES_EXPKEY_WORDS 32 -#define DES_BLOCK_SIZE 8 - -#define DES3_EDE_KEY_SIZE (3 * DES_KEY_SIZE) -#define DES3_EDE_EXPKEY_WORDS (3 * DES_EXPKEY_WORDS) -#define DES3_EDE_BLOCK_SIZE DES_BLOCK_SIZE +#include <crypto/des.h> #define ROL(x, r) ((x) = rol32((x), (r))) #define ROR(x, r) ((x) = ror32((x), (r))) @@ -634,7 +628,7 @@ static const u32 S8[64] = { * Choice 1 has operated on the key. * */ -static unsigned long ekey(u32 *pe, const u8 *k) +unsigned long des_ekey(u32 *pe, const u8 *k) { /* K&R: long is at least 32 bits */ unsigned long a, b, c, d, w; @@ -709,6 +703,7 @@ static unsigned long ekey(u32 *pe, const u8 *k) /* Zero if weak key */ return w; } +EXPORT_SYMBOL_GPL(des_ekey); /* * Decryption key expansion @@ -792,7 +787,7 @@ static int des_setkey(struct crypto_tfm *tfm, const u8 *key, int ret; /* Expand to tmp */ - ret = ekey(tmp, key); + ret = des_ekey(tmp, key); if (unlikely(ret == 0) && (*flags & CRYPTO_TFM_REQ_WEAK_KEY)) { *flags |= CRYPTO_TFM_RES_WEAK_KEY; @@ -879,9 +874,9 @@ static int des3_ede_setkey(struct crypto_tfm *tfm, const u8 *key, return -EINVAL; } - ekey(expkey, key); expkey += DES_EXPKEY_WORDS; key += DES_KEY_SIZE; + des_ekey(expkey, key); expkey += DES_EXPKEY_WORDS; key += DES_KEY_SIZE; dkey(expkey, key); expkey += DES_EXPKEY_WORDS; key += DES_KEY_SIZE; - ekey(expkey, key); + des_ekey(expkey, key); return 0; } diff --git a/crypto/digest.c b/crypto/digest.c index 8871dec8cae7..6fd43bddd545 100644 --- a/crypto/digest.c +++ b/crypto/digest.c @@ -12,6 +12,7 @@ * */ +#include <crypto/scatterwalk.h> #include <linux/mm.h> #include <linux/errno.h> #include <linux/hardirq.h> @@ -20,9 +21,6 @@ #include <linux/module.h> #include <linux/scatterlist.h> -#include "internal.h" -#include "scatterwalk.h" - static int init(struct hash_desc *desc) { struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm); diff --git a/crypto/eseqiv.c b/crypto/eseqiv.c new file mode 100644 index 000000000000..eb90d27ae118 --- /dev/null +++ b/crypto/eseqiv.c @@ -0,0 +1,264 @@ +/* + * eseqiv: Encrypted Sequence Number IV Generator + * + * This generator generates an IV based on a sequence number by xoring it + * with a salt and then encrypting it with the same key as used to encrypt + * the plain text. This algorithm requires that the block size be equal + * to the IV size. It is mainly useful for CBC. + * + * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au> + * + * 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. + * + */ + +#include <crypto/internal/skcipher.h> +#include <crypto/scatterwalk.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/random.h> +#include <linux/scatterlist.h> +#include <linux/spinlock.h> +#include <linux/string.h> + +struct eseqiv_request_ctx { + struct scatterlist src[2]; + struct scatterlist dst[2]; + char tail[]; +}; + +struct eseqiv_ctx { + spinlock_t lock; + unsigned int reqoff; + char salt[]; +}; + +static void eseqiv_complete2(struct skcipher_givcrypt_request *req) +{ + struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req); + struct eseqiv_request_ctx *reqctx = skcipher_givcrypt_reqctx(req); + + memcpy(req->giv, PTR_ALIGN((u8 *)reqctx->tail, + crypto_ablkcipher_alignmask(geniv) + 1), + crypto_ablkcipher_ivsize(geniv)); +} + +static void eseqiv_complete(struct crypto_async_request *base, int err) +{ + struct skcipher_givcrypt_request *req = base->data; + + if (err) + goto out; + + eseqiv_complete2(req); + +out: + skcipher_givcrypt_complete(req, err); +} + +static void eseqiv_chain(struct scatterlist *head, struct scatterlist *sg, + int chain) +{ + if (chain) { + head->length += sg->length; + sg = scatterwalk_sg_next(sg); + } + + if (sg) + scatterwalk_sg_chain(head, 2, sg); + else + sg_mark_end(head); +} + +static int eseqiv_givencrypt(struct skcipher_givcrypt_request *req) +{ + struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req); + struct eseqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv); + struct eseqiv_request_ctx *reqctx = skcipher_givcrypt_reqctx(req); + struct ablkcipher_request *subreq; + crypto_completion_t complete; + void *data; + struct scatterlist *osrc, *odst; + struct scatterlist *dst; + struct page *srcp; + struct page *dstp; + u8 *giv; + u8 *vsrc; + u8 *vdst; + __be64 seq; + unsigned int ivsize; + unsigned int len; + int err; + + subreq = (void *)(reqctx->tail + ctx->reqoff); + ablkcipher_request_set_tfm(subreq, skcipher_geniv_cipher(geniv)); + + giv = req->giv; + complete = req->creq.base.complete; + data = req->creq.base.data; + + osrc = req->creq.src; + odst = req->creq.dst; + srcp = sg_page(osrc); + dstp = sg_page(odst); + vsrc = PageHighMem(srcp) ? NULL : page_address(srcp) + osrc->offset; + vdst = PageHighMem(dstp) ? NULL : page_address(dstp) + odst->offset; + + ivsize = crypto_ablkcipher_ivsize(geniv); + + if (vsrc != giv + ivsize && vdst != giv + ivsize) { + giv = PTR_ALIGN((u8 *)reqctx->tail, + crypto_ablkcipher_alignmask(geniv) + 1); + complete = eseqiv_complete; + data = req; + } + + ablkcipher_request_set_callback(subreq, req->creq.base.flags, complete, + data); + + sg_init_table(reqctx->src, 2); + sg_set_buf(reqctx->src, giv, ivsize); + eseqiv_chain(reqctx->src, osrc, vsrc == giv + ivsize); + + dst = reqctx->src; + if (osrc != odst) { + sg_init_table(reqctx->dst, 2); + sg_set_buf(reqctx->dst, giv, ivsize); + eseqiv_chain(reqctx->dst, odst, vdst == giv + ivsize); + + dst = reqctx->dst; + } + + ablkcipher_request_set_crypt(subreq, reqctx->src, dst, + req->creq.nbytes, req->creq.info); + + memcpy(req->creq.info, ctx->salt, ivsize); + + len = ivsize; + if (ivsize > sizeof(u64)) { + memset(req->giv, 0, ivsize - sizeof(u64)); + len = sizeof(u64); + } + seq = cpu_to_be64(req->seq); + memcpy(req->giv + ivsize - len, &seq, len); + + err = crypto_ablkcipher_encrypt(subreq); + if (err) + goto out; + + eseqiv_complete2(req); + +out: + return err; +} + +static int eseqiv_givencrypt_first(struct skcipher_givcrypt_request *req) +{ + struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req); + struct eseqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv); + + spin_lock_bh(&ctx->lock); + if (crypto_ablkcipher_crt(geniv)->givencrypt != eseqiv_givencrypt_first) + goto unlock; + + crypto_ablkcipher_crt(geniv)->givencrypt = eseqiv_givencrypt; + get_random_bytes(ctx->salt, crypto_ablkcipher_ivsize(geniv)); + +unlock: + spin_unlock_bh(&ctx->lock); + + return eseqiv_givencrypt(req); +} + +static int eseqiv_init(struct crypto_tfm *tfm) +{ + struct crypto_ablkcipher *geniv = __crypto_ablkcipher_cast(tfm); + struct eseqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv); + unsigned long alignmask; + unsigned int reqsize; + + spin_lock_init(&ctx->lock); + + alignmask = crypto_tfm_ctx_alignment() - 1; + reqsize = sizeof(struct eseqiv_request_ctx); + + if (alignmask & reqsize) { + alignmask &= reqsize; + alignmask--; + } + + alignmask = ~alignmask; + alignmask &= crypto_ablkcipher_alignmask(geniv); + + reqsize += alignmask; + reqsize += crypto_ablkcipher_ivsize(geniv); + reqsize = ALIGN(reqsize, crypto_tfm_ctx_alignment()); + + ctx->reqoff = reqsize - sizeof(struct eseqiv_request_ctx); + + tfm->crt_ablkcipher.reqsize = reqsize + + sizeof(struct ablkcipher_request); + + return skcipher_geniv_init(tfm); +} + +static struct crypto_template eseqiv_tmpl; + +static struct crypto_instance *eseqiv_alloc(struct rtattr **tb) +{ + struct crypto_instance *inst; + int err; + + inst = skcipher_geniv_alloc(&eseqiv_tmpl, tb, 0, 0); + if (IS_ERR(inst)) + goto out; + + err = -EINVAL; + if (inst->alg.cra_ablkcipher.ivsize != inst->alg.cra_blocksize) + goto free_inst; + + inst->alg.cra_ablkcipher.givencrypt = eseqiv_givencrypt_first; + + inst->alg.cra_init = eseqiv_init; + inst->alg.cra_exit = skcipher_geniv_exit; + + inst->alg.cra_ctxsize = sizeof(struct eseqiv_ctx); + inst->alg.cra_ctxsize += inst->alg.cra_ablkcipher.ivsize; + +out: + return inst; + +free_inst: + skcipher_geniv_free(inst); + inst = ERR_PTR(err); + goto out; +} + +static struct crypto_template eseqiv_tmpl = { + .name = "eseqiv", + .alloc = eseqiv_alloc, + .free = skcipher_geniv_free, + .module = THIS_MODULE, +}; + +static int __init eseqiv_module_init(void) +{ + return crypto_register_template(&eseqiv_tmpl); +} + +static void __exit eseqiv_module_exit(void) +{ + crypto_unregister_template(&eseqiv_tmpl); +} + +module_init(eseqiv_module_init); +module_exit(eseqiv_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Encrypted Sequence Number IV Generator"); diff --git a/crypto/gcm.c b/crypto/gcm.c new file mode 100644 index 000000000000..e70afd0c73dd --- /dev/null +++ b/crypto/gcm.c @@ -0,0 +1,823 @@ +/* + * GCM: Galois/Counter Mode. + * + * Copyright (c) 2007 Nokia Siemens Networks - Mikko Herranen <mh1@iki.fi> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include <crypto/gf128mul.h> +#include <crypto/internal/aead.h> +#include <crypto/internal/skcipher.h> +#include <crypto/scatterwalk.h> +#include <linux/completion.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> + +struct gcm_instance_ctx { + struct crypto_skcipher_spawn ctr; +}; + +struct crypto_gcm_ctx { + struct crypto_ablkcipher *ctr; + struct gf128mul_4k *gf128; +}; + +struct crypto_rfc4106_ctx { + struct crypto_aead *child; + u8 nonce[4]; +}; + +struct crypto_gcm_ghash_ctx { + u32 bytes; + u32 flags; + struct gf128mul_4k *gf128; + u8 buffer[16]; +}; + +struct crypto_gcm_req_priv_ctx { + u8 auth_tag[16]; + u8 iauth_tag[16]; + struct scatterlist src[2]; + struct scatterlist dst[2]; + struct crypto_gcm_ghash_ctx ghash; + struct ablkcipher_request abreq; +}; + +struct crypto_gcm_setkey_result { + int err; + struct completion completion; +}; + +static inline struct crypto_gcm_req_priv_ctx *crypto_gcm_reqctx( + struct aead_request *req) +{ + unsigned long align = crypto_aead_alignmask(crypto_aead_reqtfm(req)); + + return (void *)PTR_ALIGN((u8 *)aead_request_ctx(req), align + 1); +} + +static void crypto_gcm_ghash_init(struct crypto_gcm_ghash_ctx *ctx, u32 flags, + struct gf128mul_4k *gf128) +{ + ctx->bytes = 0; + ctx->flags = flags; + ctx->gf128 = gf128; + memset(ctx->buffer, 0, 16); +} + +static void crypto_gcm_ghash_update(struct crypto_gcm_ghash_ctx *ctx, + const u8 *src, unsigned int srclen) +{ + u8 *dst = ctx->buffer; + + if (ctx->bytes) { + int n = min(srclen, ctx->bytes); + u8 *pos = dst + (16 - ctx->bytes); + + ctx->bytes -= n; + srclen -= n; + + while (n--) + *pos++ ^= *src++; + + if (!ctx->bytes) + gf128mul_4k_lle((be128 *)dst, ctx->gf128); + } + + while (srclen >= 16) { + crypto_xor(dst, src, 16); + gf128mul_4k_lle((be128 *)dst, ctx->gf128); + src += 16; + srclen -= 16; + } + + if (srclen) { + ctx->bytes = 16 - srclen; + while (srclen--) + *dst++ ^= *src++; + } +} + +static void crypto_gcm_ghash_update_sg(struct crypto_gcm_ghash_ctx *ctx, + struct scatterlist *sg, int len) +{ + struct scatter_walk walk; + u8 *src; + int n; + + if (!len) + return; + + scatterwalk_start(&walk, sg); + + while (len) { + n = scatterwalk_clamp(&walk, len); + + if (!n) { + scatterwalk_start(&walk, scatterwalk_sg_next(walk.sg)); + n = scatterwalk_clamp(&walk, len); + } + + src = scatterwalk_map(&walk, 0); + + crypto_gcm_ghash_update(ctx, src, n); + len -= n; + + scatterwalk_unmap(src, 0); + scatterwalk_advance(&walk, n); + scatterwalk_done(&walk, 0, len); + if (len) + crypto_yield(ctx->flags); + } +} + +static void crypto_gcm_ghash_flush(struct crypto_gcm_ghash_ctx *ctx) +{ + u8 *dst = ctx->buffer; + + if (ctx->bytes) { + u8 *tmp = dst + (16 - ctx->bytes); + + while (ctx->bytes--) + *tmp++ ^= 0; + + gf128mul_4k_lle((be128 *)dst, ctx->gf128); + } + + ctx->bytes = 0; +} + +static void crypto_gcm_ghash_final_xor(struct crypto_gcm_ghash_ctx *ctx, + unsigned int authlen, + unsigned int cryptlen, u8 *dst) +{ + u8 *buf = ctx->buffer; + u128 lengths; + + lengths.a = cpu_to_be64(authlen * 8); + lengths.b = cpu_to_be64(cryptlen * 8); + + crypto_gcm_ghash_flush(ctx); + crypto_xor(buf, (u8 *)&lengths, 16); + gf128mul_4k_lle((be128 *)buf, ctx->gf128); + crypto_xor(dst, buf, 16); +} + +static void crypto_gcm_setkey_done(struct crypto_async_request *req, int err) +{ + struct crypto_gcm_setkey_result *result = req->data; + + if (err == -EINPROGRESS) + return; + + result->err = err; + complete(&result->completion); +} + +static int crypto_gcm_setkey(struct crypto_aead *aead, const u8 *key, + unsigned int keylen) +{ + struct crypto_gcm_ctx *ctx = crypto_aead_ctx(aead); + struct crypto_ablkcipher *ctr = ctx->ctr; + struct { + be128 hash; + u8 iv[8]; + + struct crypto_gcm_setkey_result result; + + struct scatterlist sg[1]; + struct ablkcipher_request req; + } *data; + int err; + + crypto_ablkcipher_clear_flags(ctr, CRYPTO_TFM_REQ_MASK); + crypto_ablkcipher_set_flags(ctr, crypto_aead_get_flags(aead) & + CRYPTO_TFM_REQ_MASK); + + err = crypto_ablkcipher_setkey(ctr, key, keylen); + if (err) + return err; + + crypto_aead_set_flags(aead, crypto_ablkcipher_get_flags(ctr) & + CRYPTO_TFM_RES_MASK); + + data = kzalloc(sizeof(*data) + crypto_ablkcipher_reqsize(ctr), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + init_completion(&data->result.completion); + sg_init_one(data->sg, &data->hash, sizeof(data->hash)); + ablkcipher_request_set_tfm(&data->req, ctr); + ablkcipher_request_set_callback(&data->req, CRYPTO_TFM_REQ_MAY_SLEEP | + CRYPTO_TFM_REQ_MAY_BACKLOG, + crypto_gcm_setkey_done, + &data->result); + ablkcipher_request_set_crypt(&data->req, data->sg, data->sg, + sizeof(data->hash), data->iv); + + err = crypto_ablkcipher_encrypt(&data->req); + if (err == -EINPROGRESS || err == -EBUSY) { + err = wait_for_completion_interruptible( + &data->result.completion); + if (!err) + err = data->result.err; + } + + if (err) + goto out; + + if (ctx->gf128 != NULL) + gf128mul_free_4k(ctx->gf128); + + ctx->gf128 = gf128mul_init_4k_lle(&data->hash); + + if (ctx->gf128 == NULL) + err = -ENOMEM; + +out: + kfree(data); + return err; +} + +static int crypto_gcm_setauthsize(struct crypto_aead *tfm, + unsigned int authsize) +{ + switch (authsize) { + case 4: + case 8: + case 12: + case 13: + case 14: + case 15: + case 16: + break; + default: + return -EINVAL; + } + + return 0; +} + +static void crypto_gcm_init_crypt(struct ablkcipher_request *ablk_req, + struct aead_request *req, + unsigned int cryptlen) +{ + struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct crypto_gcm_ctx *ctx = crypto_aead_ctx(aead); + struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); + u32 flags = req->base.tfm->crt_flags; + struct crypto_gcm_ghash_ctx *ghash = &pctx->ghash; + struct scatterlist *dst; + __be32 counter = cpu_to_be32(1); + + memset(pctx->auth_tag, 0, sizeof(pctx->auth_tag)); + memcpy(req->iv + 12, &counter, 4); + + sg_init_table(pctx->src, 2); + sg_set_buf(pctx->src, pctx->auth_tag, sizeof(pctx->auth_tag)); + scatterwalk_sg_chain(pctx->src, 2, req->src); + + dst = pctx->src; + if (req->src != req->dst) { + sg_init_table(pctx->dst, 2); + sg_set_buf(pctx->dst, pctx->auth_tag, sizeof(pctx->auth_tag)); + scatterwalk_sg_chain(pctx->dst, 2, req->dst); + dst = pctx->dst; + } + + ablkcipher_request_set_tfm(ablk_req, ctx->ctr); + ablkcipher_request_set_crypt(ablk_req, pctx->src, dst, + cryptlen + sizeof(pctx->auth_tag), + req->iv); + + crypto_gcm_ghash_init(ghash, flags, ctx->gf128); + + crypto_gcm_ghash_update_sg(ghash, req->assoc, req->assoclen); + crypto_gcm_ghash_flush(ghash); +} + +static int crypto_gcm_hash(struct aead_request *req) +{ + struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); + u8 *auth_tag = pctx->auth_tag; + struct crypto_gcm_ghash_ctx *ghash = &pctx->ghash; + + crypto_gcm_ghash_update_sg(ghash, req->dst, req->cryptlen); + crypto_gcm_ghash_final_xor(ghash, req->assoclen, req->cryptlen, + auth_tag); + + scatterwalk_map_and_copy(auth_tag, req->dst, req->cryptlen, + crypto_aead_authsize(aead), 1); + return 0; +} + +static void crypto_gcm_encrypt_done(struct crypto_async_request *areq, int err) +{ + struct aead_request *req = areq->data; + + if (!err) + err = crypto_gcm_hash(req); + + aead_request_complete(req, err); +} + +static int crypto_gcm_encrypt(struct aead_request *req) +{ + struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); + struct ablkcipher_request *abreq = &pctx->abreq; + int err; + + crypto_gcm_init_crypt(abreq, req, req->cryptlen); + ablkcipher_request_set_callback(abreq, aead_request_flags(req), + crypto_gcm_encrypt_done, req); + + err = crypto_ablkcipher_encrypt(abreq); + if (err) + return err; + + return crypto_gcm_hash(req); +} + +static int crypto_gcm_verify(struct aead_request *req) +{ + struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); + struct crypto_gcm_ghash_ctx *ghash = &pctx->ghash; + u8 *auth_tag = pctx->auth_tag; + u8 *iauth_tag = pctx->iauth_tag; + unsigned int authsize = crypto_aead_authsize(aead); + unsigned int cryptlen = req->cryptlen - authsize; + + crypto_gcm_ghash_final_xor(ghash, req->assoclen, cryptlen, auth_tag); + + authsize = crypto_aead_authsize(aead); + scatterwalk_map_and_copy(iauth_tag, req->src, cryptlen, authsize, 0); + return memcmp(iauth_tag, auth_tag, authsize) ? -EBADMSG : 0; +} + +static void crypto_gcm_decrypt_done(struct crypto_async_request *areq, int err) +{ + struct aead_request *req = areq->data; + + if (!err) + err = crypto_gcm_verify(req); + + aead_request_complete(req, err); +} + +static int crypto_gcm_decrypt(struct aead_request *req) +{ + struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); + struct ablkcipher_request *abreq = &pctx->abreq; + struct crypto_gcm_ghash_ctx *ghash = &pctx->ghash; + unsigned int cryptlen = req->cryptlen; + unsigned int authsize = crypto_aead_authsize(aead); + int err; + + if (cryptlen < authsize) + return -EINVAL; + cryptlen -= authsize; + + crypto_gcm_init_crypt(abreq, req, cryptlen); + ablkcipher_request_set_callback(abreq, aead_request_flags(req), + crypto_gcm_decrypt_done, req); + + crypto_gcm_ghash_update_sg(ghash, req->src, cryptlen); + + err = crypto_ablkcipher_decrypt(abreq); + if (err) + return err; + + return crypto_gcm_verify(req); +} + +static int crypto_gcm_init_tfm(struct crypto_tfm *tfm) +{ + struct crypto_instance *inst = (void *)tfm->__crt_alg; + struct gcm_instance_ctx *ictx = crypto_instance_ctx(inst); + struct crypto_gcm_ctx *ctx = crypto_tfm_ctx(tfm); + struct crypto_ablkcipher *ctr; + unsigned long align; + int err; + + ctr = crypto_spawn_skcipher(&ictx->ctr); + err = PTR_ERR(ctr); + if (IS_ERR(ctr)) + return err; + + ctx->ctr = ctr; + ctx->gf128 = NULL; + + align = crypto_tfm_alg_alignmask(tfm); + align &= ~(crypto_tfm_ctx_alignment() - 1); + tfm->crt_aead.reqsize = align + + sizeof(struct crypto_gcm_req_priv_ctx) + + crypto_ablkcipher_reqsize(ctr); + + return 0; +} + +static void crypto_gcm_exit_tfm(struct crypto_tfm *tfm) +{ + struct crypto_gcm_ctx *ctx = crypto_tfm_ctx(tfm); + + if (ctx->gf128 != NULL) + gf128mul_free_4k(ctx->gf128); + + crypto_free_ablkcipher(ctx->ctr); +} + +static struct crypto_instance *crypto_gcm_alloc_common(struct rtattr **tb, + const char *full_name, + const char *ctr_name) +{ + struct crypto_attr_type *algt; + struct crypto_instance *inst; + struct crypto_alg *ctr; + struct gcm_instance_ctx *ctx; + int err; + + algt = crypto_get_attr_type(tb); + err = PTR_ERR(algt); + if (IS_ERR(algt)) + return ERR_PTR(err); + + if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask) + return ERR_PTR(-EINVAL); + + inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL); + if (!inst) + return ERR_PTR(-ENOMEM); + + ctx = crypto_instance_ctx(inst); + crypto_set_skcipher_spawn(&ctx->ctr, inst); + err = crypto_grab_skcipher(&ctx->ctr, ctr_name, 0, + crypto_requires_sync(algt->type, + algt->mask)); + if (err) + goto err_free_inst; + + ctr = crypto_skcipher_spawn_alg(&ctx->ctr); + + /* We only support 16-byte blocks. */ + if (ctr->cra_ablkcipher.ivsize != 16) + goto out_put_ctr; + + /* Not a stream cipher? */ + err = -EINVAL; + if (ctr->cra_blocksize != 1) + goto out_put_ctr; + + err = -ENAMETOOLONG; + if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, + "gcm_base(%s)", ctr->cra_driver_name) >= + CRYPTO_MAX_ALG_NAME) + goto out_put_ctr; + + memcpy(inst->alg.cra_name, full_name, CRYPTO_MAX_ALG_NAME); + + inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD; + inst->alg.cra_flags |= ctr->cra_flags & CRYPTO_ALG_ASYNC; + inst->alg.cra_priority = ctr->cra_priority; + inst->alg.cra_blocksize = 1; + inst->alg.cra_alignmask = ctr->cra_alignmask | (__alignof__(u64) - 1); + inst->alg.cra_type = &crypto_aead_type; + inst->alg.cra_aead.ivsize = 16; + inst->alg.cra_aead.maxauthsize = 16; + inst->alg.cra_ctxsize = sizeof(struct crypto_gcm_ctx); + inst->alg.cra_init = crypto_gcm_init_tfm; + inst->alg.cra_exit = crypto_gcm_exit_tfm; + inst->alg.cra_aead.setkey = crypto_gcm_setkey; + inst->alg.cra_aead.setauthsize = crypto_gcm_setauthsize; + inst->alg.cra_aead.encrypt = crypto_gcm_encrypt; + inst->alg.cra_aead.decrypt = crypto_gcm_decrypt; + +out: + return inst; + +out_put_ctr: + crypto_drop_skcipher(&ctx->ctr); +err_free_inst: + kfree(inst); + inst = ERR_PTR(err); + goto out; +} + +static struct crypto_instance *crypto_gcm_alloc(struct rtattr **tb) +{ + int err; + const char *cipher_name; + char ctr_name[CRYPTO_MAX_ALG_NAME]; + char full_name[CRYPTO_MAX_ALG_NAME]; + + cipher_name = crypto_attr_alg_name(tb[1]); + err = PTR_ERR(cipher_name); + if (IS_ERR(cipher_name)) + return ERR_PTR(err); + + if (snprintf(ctr_name, CRYPTO_MAX_ALG_NAME, "ctr(%s)", cipher_name) >= + CRYPTO_MAX_ALG_NAME) + return ERR_PTR(-ENAMETOOLONG); + + if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm(%s)", cipher_name) >= + CRYPTO_MAX_ALG_NAME) + return ERR_PTR(-ENAMETOOLONG); + + return crypto_gcm_alloc_common(tb, full_name, ctr_name); +} + +static void crypto_gcm_free(struct crypto_instance *inst) +{ + struct gcm_instance_ctx *ctx = crypto_instance_ctx(inst); + + crypto_drop_skcipher(&ctx->ctr); + kfree(inst); +} + +static struct crypto_template crypto_gcm_tmpl = { + .name = "gcm", + .alloc = crypto_gcm_alloc, + .free = crypto_gcm_free, + .module = THIS_MODULE, +}; + +static struct crypto_instance *crypto_gcm_base_alloc(struct rtattr **tb) +{ + int err; + const char *ctr_name; + char full_name[CRYPTO_MAX_ALG_NAME]; + + ctr_name = crypto_attr_alg_name(tb[1]); + err = PTR_ERR(ctr_name); + if (IS_ERR(ctr_name)) + return ERR_PTR(err); + + if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm_base(%s)", + ctr_name) >= CRYPTO_MAX_ALG_NAME) + return ERR_PTR(-ENAMETOOLONG); + + return crypto_gcm_alloc_common(tb, full_name, ctr_name); +} + +static struct crypto_template crypto_gcm_base_tmpl = { + .name = "gcm_base", + .alloc = crypto_gcm_base_alloc, + .free = crypto_gcm_free, + .module = THIS_MODULE, +}; + +static int crypto_rfc4106_setkey(struct crypto_aead *parent, const u8 *key, + unsigned int keylen) +{ + struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(parent); + struct crypto_aead *child = ctx->child; + int err; + + if (keylen < 4) + return -EINVAL; + + keylen -= 4; + memcpy(ctx->nonce, key + keylen, 4); + + crypto_aead_clear_flags(child, CRYPTO_TFM_REQ_MASK); + crypto_aead_set_flags(child, crypto_aead_get_flags(parent) & + CRYPTO_TFM_REQ_MASK); + err = crypto_aead_setkey(child, key, keylen); + crypto_aead_set_flags(parent, crypto_aead_get_flags(child) & + CRYPTO_TFM_RES_MASK); + + return err; +} + +static int crypto_rfc4106_setauthsize(struct crypto_aead *parent, + unsigned int authsize) +{ + struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(parent); + + switch (authsize) { + case 8: + case 12: + case 16: + break; + default: + return -EINVAL; + } + + return crypto_aead_setauthsize(ctx->child, authsize); +} + +static struct aead_request *crypto_rfc4106_crypt(struct aead_request *req) +{ + struct aead_request *subreq = aead_request_ctx(req); + struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(aead); + struct crypto_aead *child = ctx->child; + u8 *iv = PTR_ALIGN((u8 *)(subreq + 1) + crypto_aead_reqsize(child), + crypto_aead_alignmask(child) + 1); + + memcpy(iv, ctx->nonce, 4); + memcpy(iv + 4, req->iv, 8); + + aead_request_set_tfm(subreq, child); + aead_request_set_callback(subreq, req->base.flags, req->base.complete, + req->base.data); + aead_request_set_crypt(subreq, req->src, req->dst, req->cryptlen, iv); + aead_request_set_assoc(subreq, req->assoc, req->assoclen); + + return subreq; +} + +static int crypto_rfc4106_encrypt(struct aead_request *req) +{ + req = crypto_rfc4106_crypt(req); + + return crypto_aead_encrypt(req); +} + +static int crypto_rfc4106_decrypt(struct aead_request *req) +{ + req = crypto_rfc4106_crypt(req); + + return crypto_aead_decrypt(req); +} + +static int crypto_rfc4106_init_tfm(struct crypto_tfm *tfm) +{ + struct crypto_instance *inst = (void *)tfm->__crt_alg; + struct crypto_aead_spawn *spawn = crypto_instance_ctx(inst); + struct crypto_rfc4106_ctx *ctx = crypto_tfm_ctx(tfm); + struct crypto_aead *aead; + unsigned long align; + + aead = crypto_spawn_aead(spawn); + if (IS_ERR(aead)) + return PTR_ERR(aead); + + ctx->child = aead; + + align = crypto_aead_alignmask(aead); + align &= ~(crypto_tfm_ctx_alignment() - 1); + tfm->crt_aead.reqsize = sizeof(struct aead_request) + + ALIGN(crypto_aead_reqsize(aead), + crypto_tfm_ctx_alignment()) + + align + 16; + + return 0; +} + +static void crypto_rfc4106_exit_tfm(struct crypto_tfm *tfm) +{ + struct crypto_rfc4106_ctx *ctx = crypto_tfm_ctx(tfm); + + crypto_free_aead(ctx->child); +} + +static struct crypto_instance *crypto_rfc4106_alloc(struct rtattr **tb) +{ + struct crypto_attr_type *algt; + struct crypto_instance *inst; + struct crypto_aead_spawn *spawn; + struct crypto_alg *alg; + const char *ccm_name; + int err; + + algt = crypto_get_attr_type(tb); + err = PTR_ERR(algt); + if (IS_ERR(algt)) + return ERR_PTR(err); + + if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask) + return ERR_PTR(-EINVAL); + + ccm_name = crypto_attr_alg_name(tb[1]); + err = PTR_ERR(ccm_name); + if (IS_ERR(ccm_name)) + return ERR_PTR(err); + + inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL); + if (!inst) + return ERR_PTR(-ENOMEM); + + spawn = crypto_instance_ctx(inst); + crypto_set_aead_spawn(spawn, inst); + err = crypto_grab_aead(spawn, ccm_name, 0, + crypto_requires_sync(algt->type, algt->mask)); + if (err) + goto out_free_inst; + + alg = crypto_aead_spawn_alg(spawn); + + err = -EINVAL; + + /* We only support 16-byte blocks. */ + if (alg->cra_aead.ivsize != 16) + goto out_drop_alg; + + /* Not a stream cipher? */ + if (alg->cra_blocksize != 1) + goto out_drop_alg; + + err = -ENAMETOOLONG; + if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, + "rfc4106(%s)", alg->cra_name) >= CRYPTO_MAX_ALG_NAME || + snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, + "rfc4106(%s)", alg->cra_driver_name) >= + CRYPTO_MAX_ALG_NAME) + goto out_drop_alg; + + inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD; + inst->alg.cra_flags |= alg->cra_flags & CRYPTO_ALG_ASYNC; + inst->alg.cra_priority = alg->cra_priority; + inst->alg.cra_blocksize = 1; + inst->alg.cra_alignmask = alg->cra_alignmask; + inst->alg.cra_type = &crypto_nivaead_type; + + inst->alg.cra_aead.ivsize = 8; + inst->alg.cra_aead.maxauthsize = 16; + + inst->alg.cra_ctxsize = sizeof(struct crypto_rfc4106_ctx); + + inst->alg.cra_init = crypto_rfc4106_init_tfm; + inst->alg.cra_exit = crypto_rfc4106_exit_tfm; + + inst->alg.cra_aead.setkey = crypto_rfc4106_setkey; + inst->alg.cra_aead.setauthsize = crypto_rfc4106_setauthsize; + inst->alg.cra_aead.encrypt = crypto_rfc4106_encrypt; + inst->alg.cra_aead.decrypt = crypto_rfc4106_decrypt; + + inst->alg.cra_aead.geniv = "seqiv"; + +out: + return inst; + +out_drop_alg: + crypto_drop_aead(spawn); +out_free_inst: + kfree(inst); + inst = ERR_PTR(err); + goto out; +} + +static void crypto_rfc4106_free(struct crypto_instance *inst) +{ + crypto_drop_spawn(crypto_instance_ctx(inst)); + kfree(inst); +} + +static struct crypto_template crypto_rfc4106_tmpl = { + .name = "rfc4106", + .alloc = crypto_rfc4106_alloc, + .free = crypto_rfc4106_free, + .module = THIS_MODULE, +}; + +static int __init crypto_gcm_module_init(void) +{ + int err; + + err = crypto_register_template(&crypto_gcm_base_tmpl); + if (err) + goto out; + + err = crypto_register_template(&crypto_gcm_tmpl); + if (err) + goto out_undo_base; + + err = crypto_register_template(&crypto_rfc4106_tmpl); + if (err) + goto out_undo_gcm; + +out: + return err; + +out_undo_gcm: + crypto_unregister_template(&crypto_gcm_tmpl); +out_undo_base: + crypto_unregister_template(&crypto_gcm_base_tmpl); + goto out; +} + +static void __exit crypto_gcm_module_exit(void) +{ + crypto_unregister_template(&crypto_rfc4106_tmpl); + crypto_unregister_template(&crypto_gcm_tmpl); + crypto_unregister_template(&crypto_gcm_base_tmpl); +} + +module_init(crypto_gcm_module_init); +module_exit(crypto_gcm_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Galois/Counter Mode"); +MODULE_AUTHOR("Mikko Herranen <mh1@iki.fi>"); +MODULE_ALIAS("gcm_base"); +MODULE_ALIAS("rfc4106"); diff --git a/crypto/hmac.c b/crypto/hmac.c index 0f05be769c34..a1d016a50e7d 100644 --- a/crypto/hmac.c +++ b/crypto/hmac.c @@ -17,6 +17,7 @@ */ #include <crypto/algapi.h> +#include <crypto/scatterwalk.h> #include <linux/err.h> #include <linux/init.h> #include <linux/kernel.h> @@ -160,7 +161,7 @@ static int hmac_digest(struct hash_desc *pdesc, struct scatterlist *sg, sg_init_table(sg1, 2); sg_set_buf(sg1, ipad, bs); - sg_set_page(&sg1[1], (void *) sg, 0, 0); + scatterwalk_sg_chain(sg1, 2, sg); sg_init_table(sg2, 1); sg_set_buf(sg2, opad, bs + ds); diff --git a/crypto/internal.h b/crypto/internal.h index abb01f71f817..32f4c2145603 100644 --- a/crypto/internal.h +++ b/crypto/internal.h @@ -25,7 +25,6 @@ #include <linux/notifier.h> #include <linux/rwsem.h> #include <linux/slab.h> -#include <asm/kmap_types.h> /* Crypto notification events. */ enum { @@ -50,34 +49,6 @@ extern struct list_head crypto_alg_list; extern struct rw_semaphore crypto_alg_sem; extern struct blocking_notifier_head crypto_chain; -static inline enum km_type crypto_kmap_type(int out) -{ - enum km_type type; - - if (in_softirq()) - type = out * (KM_SOFTIRQ1 - KM_SOFTIRQ0) + KM_SOFTIRQ0; - else - type = out * (KM_USER1 - KM_USER0) + KM_USER0; - - return type; -} - -static inline void *crypto_kmap(struct page *page, int out) -{ - return kmap_atomic(page, crypto_kmap_type(out)); -} - -static inline void crypto_kunmap(void *vaddr, int out) -{ - kunmap_atomic(vaddr, crypto_kmap_type(out)); -} - -static inline void crypto_yield(u32 flags) -{ - if (flags & CRYPTO_TFM_REQ_MAY_SLEEP) - cond_resched(); -} - #ifdef CONFIG_PROC_FS void __init crypto_init_proc(void); void __exit crypto_exit_proc(void); @@ -122,6 +93,8 @@ void crypto_exit_digest_ops(struct crypto_tfm *tfm); void crypto_exit_cipher_ops(struct crypto_tfm *tfm); void crypto_exit_compress_ops(struct crypto_tfm *tfm); +void crypto_larval_kill(struct crypto_alg *alg); +struct crypto_alg *crypto_larval_lookup(const char *name, u32 type, u32 mask); void crypto_larval_error(const char *name, u32 type, u32 mask); void crypto_shoot_alg(struct crypto_alg *alg); diff --git a/crypto/lzo.c b/crypto/lzo.c new file mode 100644 index 000000000000..48c32883f024 --- /dev/null +++ b/crypto/lzo.c @@ -0,0 +1,106 @@ +/* + * Cryptographic API. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * 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 + * + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/crypto.h> +#include <linux/vmalloc.h> +#include <linux/lzo.h> + +struct lzo_ctx { + void *lzo_comp_mem; +}; + +static int lzo_init(struct crypto_tfm *tfm) +{ + struct lzo_ctx *ctx = crypto_tfm_ctx(tfm); + + ctx->lzo_comp_mem = vmalloc(LZO1X_MEM_COMPRESS); + if (!ctx->lzo_comp_mem) + return -ENOMEM; + + return 0; +} + +static void lzo_exit(struct crypto_tfm *tfm) +{ + struct lzo_ctx *ctx = crypto_tfm_ctx(tfm); + + vfree(ctx->lzo_comp_mem); +} + +static int lzo_compress(struct crypto_tfm *tfm, const u8 *src, + unsigned int slen, u8 *dst, unsigned int *dlen) +{ + struct lzo_ctx *ctx = crypto_tfm_ctx(tfm); + size_t tmp_len = *dlen; /* size_t(ulong) <-> uint on 64 bit */ + int err; + + err = lzo1x_1_compress(src, slen, dst, &tmp_len, ctx->lzo_comp_mem); + + if (err != LZO_E_OK) + return -EINVAL; + + *dlen = tmp_len; + return 0; +} + +static int lzo_decompress(struct crypto_tfm *tfm, const u8 *src, + unsigned int slen, u8 *dst, unsigned int *dlen) +{ + int err; + size_t tmp_len = *dlen; /* size_t(ulong) <-> uint on 64 bit */ + + err = lzo1x_decompress_safe(src, slen, dst, &tmp_len); + + if (err != LZO_E_OK) + return -EINVAL; + + *dlen = tmp_len; + return 0; + +} + +static struct crypto_alg alg = { + .cra_name = "lzo", + .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, + .cra_ctxsize = sizeof(struct lzo_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(alg.cra_list), + .cra_init = lzo_init, + .cra_exit = lzo_exit, + .cra_u = { .compress = { + .coa_compress = lzo_compress, + .coa_decompress = lzo_decompress } } +}; + +static int __init init(void) +{ + return crypto_register_alg(&alg); +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&alg); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("LZO Compression Algorithm"); diff --git a/crypto/pcbc.c b/crypto/pcbc.c index c3ed8a1c9f46..fe704775f88f 100644 --- a/crypto/pcbc.c +++ b/crypto/pcbc.c @@ -24,7 +24,6 @@ struct crypto_pcbc_ctx { struct crypto_cipher *child; - void (*xor)(u8 *dst, const u8 *src, unsigned int bs); }; static int crypto_pcbc_setkey(struct crypto_tfm *parent, const u8 *key, @@ -45,9 +44,7 @@ static int crypto_pcbc_setkey(struct crypto_tfm *parent, const u8 *key, static int crypto_pcbc_encrypt_segment(struct blkcipher_desc *desc, struct blkcipher_walk *walk, - struct crypto_cipher *tfm, - void (*xor)(u8 *, const u8 *, - unsigned int)) + struct crypto_cipher *tfm) { void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = crypto_cipher_alg(tfm)->cia_encrypt; @@ -58,10 +55,10 @@ static int crypto_pcbc_encrypt_segment(struct blkcipher_desc *desc, u8 *iv = walk->iv; do { - xor(iv, src, bsize); + crypto_xor(iv, src, bsize); fn(crypto_cipher_tfm(tfm), dst, iv); memcpy(iv, dst, bsize); - xor(iv, src, bsize); + crypto_xor(iv, src, bsize); src += bsize; dst += bsize; @@ -72,9 +69,7 @@ static int crypto_pcbc_encrypt_segment(struct blkcipher_desc *desc, static int crypto_pcbc_encrypt_inplace(struct blkcipher_desc *desc, struct blkcipher_walk *walk, - struct crypto_cipher *tfm, - void (*xor)(u8 *, const u8 *, - unsigned int)) + struct crypto_cipher *tfm) { void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = crypto_cipher_alg(tfm)->cia_encrypt; @@ -86,10 +81,10 @@ static int crypto_pcbc_encrypt_inplace(struct blkcipher_desc *desc, do { memcpy(tmpbuf, src, bsize); - xor(iv, tmpbuf, bsize); + crypto_xor(iv, src, bsize); fn(crypto_cipher_tfm(tfm), src, iv); - memcpy(iv, src, bsize); - xor(iv, tmpbuf, bsize); + memcpy(iv, tmpbuf, bsize); + crypto_xor(iv, src, bsize); src += bsize; } while ((nbytes -= bsize) >= bsize); @@ -107,7 +102,6 @@ static int crypto_pcbc_encrypt(struct blkcipher_desc *desc, struct crypto_blkcipher *tfm = desc->tfm; struct crypto_pcbc_ctx *ctx = crypto_blkcipher_ctx(tfm); struct crypto_cipher *child = ctx->child; - void (*xor)(u8 *, const u8 *, unsigned int bs) = ctx->xor; int err; blkcipher_walk_init(&walk, dst, src, nbytes); @@ -115,11 +109,11 @@ static int crypto_pcbc_encrypt(struct blkcipher_desc *desc, while ((nbytes = walk.nbytes)) { if (walk.src.virt.addr == walk.dst.virt.addr) - nbytes = crypto_pcbc_encrypt_inplace(desc, &walk, child, - xor); + nbytes = crypto_pcbc_encrypt_inplace(desc, &walk, + child); else - nbytes = crypto_pcbc_encrypt_segment(desc, &walk, child, - xor); + nbytes = crypto_pcbc_encrypt_segment(desc, &walk, + child); err = blkcipher_walk_done(desc, &walk, nbytes); } @@ -128,9 +122,7 @@ static int crypto_pcbc_encrypt(struct blkcipher_desc *desc, static int crypto_pcbc_decrypt_segment(struct blkcipher_desc *desc, struct blkcipher_walk *walk, - struct crypto_cipher *tfm, - void (*xor)(u8 *, const u8 *, - unsigned int)) + struct crypto_cipher *tfm) { void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = crypto_cipher_alg(tfm)->cia_decrypt; @@ -142,9 +134,9 @@ static int crypto_pcbc_decrypt_segment(struct blkcipher_desc *desc, do { fn(crypto_cipher_tfm(tfm), dst, src); - xor(dst, iv, bsize); + crypto_xor(dst, iv, bsize); memcpy(iv, src, bsize); - xor(iv, dst, bsize); + crypto_xor(iv, dst, bsize); src += bsize; dst += bsize; @@ -157,9 +149,7 @@ static int crypto_pcbc_decrypt_segment(struct blkcipher_desc *desc, static int crypto_pcbc_decrypt_inplace(struct blkcipher_desc *desc, struct blkcipher_walk *walk, - struct crypto_cipher *tfm, - void (*xor)(u8 *, const u8 *, - unsigned int)) + struct crypto_cipher *tfm) { void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = crypto_cipher_alg(tfm)->cia_decrypt; @@ -172,9 +162,9 @@ static int crypto_pcbc_decrypt_inplace(struct blkcipher_desc *desc, do { memcpy(tmpbuf, src, bsize); fn(crypto_cipher_tfm(tfm), src, src); - xor(src, iv, bsize); + crypto_xor(src, iv, bsize); memcpy(iv, tmpbuf, bsize); - xor(iv, src, bsize); + crypto_xor(iv, src, bsize); src += bsize; } while ((nbytes -= bsize) >= bsize); @@ -192,7 +182,6 @@ static int crypto_pcbc_decrypt(struct blkcipher_desc *desc, struct crypto_blkcipher *tfm = desc->tfm; struct crypto_pcbc_ctx *ctx = crypto_blkcipher_ctx(tfm); struct crypto_cipher *child = ctx->child; - void (*xor)(u8 *, const u8 *, unsigned int bs) = ctx->xor; int err; blkcipher_walk_init(&walk, dst, src, nbytes); @@ -200,48 +189,17 @@ static int crypto_pcbc_decrypt(struct blkcipher_desc *desc, while ((nbytes = walk.nbytes)) { if (walk.src.virt.addr == walk.dst.virt.addr) - nbytes = crypto_pcbc_decrypt_inplace(desc, &walk, child, - xor); + nbytes = crypto_pcbc_decrypt_inplace(desc, &walk, + child); else - nbytes = crypto_pcbc_decrypt_segment(desc, &walk, child, - xor); + nbytes = crypto_pcbc_decrypt_segment(desc, &walk, + child); err = blkcipher_walk_done(desc, &walk, nbytes); } return err; } -static void xor_byte(u8 *a, const u8 *b, unsigned int bs) -{ - do { - *a++ ^= *b++; - } while (--bs); -} - -static void xor_quad(u8 *dst, const u8 *src, unsigned int bs) -{ - u32 *a = (u32 *)dst; - u32 *b = (u32 *)src; - - do { - *a++ ^= *b++; - } while ((bs -= 4)); -} - -static void xor_64(u8 *a, const u8 *b, unsigned int bs) -{ - ((u32 *)a)[0] ^= ((u32 *)b)[0]; - ((u32 *)a)[1] ^= ((u32 *)b)[1]; -} - -static void xor_128(u8 *a, const u8 *b, unsigned int bs) -{ - ((u32 *)a)[0] ^= ((u32 *)b)[0]; - ((u32 *)a)[1] ^= ((u32 *)b)[1]; - ((u32 *)a)[2] ^= ((u32 *)b)[2]; - ((u32 *)a)[3] ^= ((u32 *)b)[3]; -} - static int crypto_pcbc_init_tfm(struct crypto_tfm *tfm) { struct crypto_instance *inst = (void *)tfm->__crt_alg; @@ -249,22 +207,6 @@ static int crypto_pcbc_init_tfm(struct crypto_tfm *tfm) struct crypto_pcbc_ctx *ctx = crypto_tfm_ctx(tfm); struct crypto_cipher *cipher; - switch (crypto_tfm_alg_blocksize(tfm)) { - case 8: - ctx->xor = xor_64; - break; - - case 16: - ctx->xor = xor_128; - break; - - default: - if (crypto_tfm_alg_blocksize(tfm) % 4) - ctx->xor = xor_byte; - else - ctx->xor = xor_quad; - } - cipher = crypto_spawn_cipher(spawn); if (IS_ERR(cipher)) return PTR_ERR(cipher); @@ -304,8 +246,9 @@ static struct crypto_instance *crypto_pcbc_alloc(struct rtattr **tb) inst->alg.cra_alignmask = alg->cra_alignmask; inst->alg.cra_type = &crypto_blkcipher_type; - if (!(alg->cra_blocksize % 4)) - inst->alg.cra_alignmask |= 3; + /* We access the data as u32s when xoring. */ + inst->alg.cra_alignmask |= __alignof__(u32) - 1; + inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize; inst->alg.cra_blkcipher.min_keysize = alg->cra_cipher.cia_min_keysize; inst->alg.cra_blkcipher.max_keysize = alg->cra_cipher.cia_max_keysize; diff --git a/crypto/salsa20_generic.c b/crypto/salsa20_generic.c new file mode 100644 index 000000000000..1fa4e4ddcab5 --- /dev/null +++ b/crypto/salsa20_generic.c @@ -0,0 +1,255 @@ +/* + * Salsa20: Salsa20 stream cipher algorithm + * + * Copyright (c) 2007 Tan Swee Heng <thesweeheng@gmail.com> + * + * Derived from: + * - salsa20.c: Public domain C code by Daniel J. Bernstein <djb@cr.yp.to> + * + * Salsa20 is a stream cipher candidate in eSTREAM, the ECRYPT Stream + * Cipher Project. It is designed by Daniel J. Bernstein <djb@cr.yp.to>. + * More information about eSTREAM and Salsa20 can be found here: + * http://www.ecrypt.eu.org/stream/ + * http://cr.yp.to/snuffle.html + * + * 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. + * + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/crypto.h> +#include <linux/types.h> +#include <crypto/algapi.h> +#include <asm/byteorder.h> + +#define SALSA20_IV_SIZE 8U +#define SALSA20_MIN_KEY_SIZE 16U +#define SALSA20_MAX_KEY_SIZE 32U + +/* + * Start of code taken from D. J. Bernstein's reference implementation. + * With some modifications and optimizations made to suit our needs. + */ + +/* +salsa20-ref.c version 20051118 +D. J. Bernstein +Public domain. +*/ + +#define ROTATE(v,n) (((v) << (n)) | ((v) >> (32 - (n)))) +#define XOR(v,w) ((v) ^ (w)) +#define PLUS(v,w) (((v) + (w))) +#define PLUSONE(v) (PLUS((v),1)) +#define U32TO8_LITTLE(p, v) \ + { (p)[0] = (v >> 0) & 0xff; (p)[1] = (v >> 8) & 0xff; \ + (p)[2] = (v >> 16) & 0xff; (p)[3] = (v >> 24) & 0xff; } +#define U8TO32_LITTLE(p) \ + (((u32)((p)[0]) ) | ((u32)((p)[1]) << 8) | \ + ((u32)((p)[2]) << 16) | ((u32)((p)[3]) << 24) ) + +struct salsa20_ctx +{ + u32 input[16]; +}; + +static void salsa20_wordtobyte(u8 output[64], const u32 input[16]) +{ + u32 x[16]; + int i; + + memcpy(x, input, sizeof(x)); + for (i = 20; i > 0; i -= 2) { + x[ 4] = XOR(x[ 4],ROTATE(PLUS(x[ 0],x[12]), 7)); + x[ 8] = XOR(x[ 8],ROTATE(PLUS(x[ 4],x[ 0]), 9)); + x[12] = XOR(x[12],ROTATE(PLUS(x[ 8],x[ 4]),13)); + x[ 0] = XOR(x[ 0],ROTATE(PLUS(x[12],x[ 8]),18)); + x[ 9] = XOR(x[ 9],ROTATE(PLUS(x[ 5],x[ 1]), 7)); + x[13] = XOR(x[13],ROTATE(PLUS(x[ 9],x[ 5]), 9)); + x[ 1] = XOR(x[ 1],ROTATE(PLUS(x[13],x[ 9]),13)); + x[ 5] = XOR(x[ 5],ROTATE(PLUS(x[ 1],x[13]),18)); + x[14] = XOR(x[14],ROTATE(PLUS(x[10],x[ 6]), 7)); + x[ 2] = XOR(x[ 2],ROTATE(PLUS(x[14],x[10]), 9)); + x[ 6] = XOR(x[ 6],ROTATE(PLUS(x[ 2],x[14]),13)); + x[10] = XOR(x[10],ROTATE(PLUS(x[ 6],x[ 2]),18)); + x[ 3] = XOR(x[ 3],ROTATE(PLUS(x[15],x[11]), 7)); + x[ 7] = XOR(x[ 7],ROTATE(PLUS(x[ 3],x[15]), 9)); + x[11] = XOR(x[11],ROTATE(PLUS(x[ 7],x[ 3]),13)); + x[15] = XOR(x[15],ROTATE(PLUS(x[11],x[ 7]),18)); + x[ 1] = XOR(x[ 1],ROTATE(PLUS(x[ 0],x[ 3]), 7)); + x[ 2] = XOR(x[ 2],ROTATE(PLUS(x[ 1],x[ 0]), 9)); + x[ 3] = XOR(x[ 3],ROTATE(PLUS(x[ 2],x[ 1]),13)); + x[ 0] = XOR(x[ 0],ROTATE(PLUS(x[ 3],x[ 2]),18)); + x[ 6] = XOR(x[ 6],ROTATE(PLUS(x[ 5],x[ 4]), 7)); + x[ 7] = XOR(x[ 7],ROTATE(PLUS(x[ 6],x[ 5]), 9)); + x[ 4] = XOR(x[ 4],ROTATE(PLUS(x[ 7],x[ 6]),13)); + x[ 5] = XOR(x[ 5],ROTATE(PLUS(x[ 4],x[ 7]),18)); + x[11] = XOR(x[11],ROTATE(PLUS(x[10],x[ 9]), 7)); + x[ 8] = XOR(x[ 8],ROTATE(PLUS(x[11],x[10]), 9)); + x[ 9] = XOR(x[ 9],ROTATE(PLUS(x[ 8],x[11]),13)); + x[10] = XOR(x[10],ROTATE(PLUS(x[ 9],x[ 8]),18)); + x[12] = XOR(x[12],ROTATE(PLUS(x[15],x[14]), 7)); + x[13] = XOR(x[13],ROTATE(PLUS(x[12],x[15]), 9)); + x[14] = XOR(x[14],ROTATE(PLUS(x[13],x[12]),13)); + x[15] = XOR(x[15],ROTATE(PLUS(x[14],x[13]),18)); + } + for (i = 0; i < 16; ++i) + x[i] = PLUS(x[i],input[i]); + for (i = 0; i < 16; ++i) + U32TO8_LITTLE(output + 4 * i,x[i]); +} + +static const char sigma[16] = "expand 32-byte k"; +static const char tau[16] = "expand 16-byte k"; + +static void salsa20_keysetup(struct salsa20_ctx *ctx, const u8 *k, u32 kbytes) +{ + const char *constants; + + ctx->input[1] = U8TO32_LITTLE(k + 0); + ctx->input[2] = U8TO32_LITTLE(k + 4); + ctx->input[3] = U8TO32_LITTLE(k + 8); + ctx->input[4] = U8TO32_LITTLE(k + 12); + if (kbytes == 32) { /* recommended */ + k += 16; + constants = sigma; + } else { /* kbytes == 16 */ + constants = tau; + } + ctx->input[11] = U8TO32_LITTLE(k + 0); + ctx->input[12] = U8TO32_LITTLE(k + 4); + ctx->input[13] = U8TO32_LITTLE(k + 8); + ctx->input[14] = U8TO32_LITTLE(k + 12); + ctx->input[0] = U8TO32_LITTLE(constants + 0); + ctx->input[5] = U8TO32_LITTLE(constants + 4); + ctx->input[10] = U8TO32_LITTLE(constants + 8); + ctx->input[15] = U8TO32_LITTLE(constants + 12); +} + +static void salsa20_ivsetup(struct salsa20_ctx *ctx, const u8 *iv) +{ + ctx->input[6] = U8TO32_LITTLE(iv + 0); + ctx->input[7] = U8TO32_LITTLE(iv + 4); + ctx->input[8] = 0; + ctx->input[9] = 0; +} + +static void salsa20_encrypt_bytes(struct salsa20_ctx *ctx, u8 *dst, + const u8 *src, unsigned int bytes) +{ + u8 buf[64]; + + if (dst != src) + memcpy(dst, src, bytes); + + while (bytes) { + salsa20_wordtobyte(buf, ctx->input); + + ctx->input[8] = PLUSONE(ctx->input[8]); + if (!ctx->input[8]) + ctx->input[9] = PLUSONE(ctx->input[9]); + + if (bytes <= 64) { + crypto_xor(dst, buf, bytes); + return; + } + + crypto_xor(dst, buf, 64); + bytes -= 64; + dst += 64; + } +} + +/* + * End of code taken from D. J. Bernstein's reference implementation. + */ + +static int setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keysize) +{ + struct salsa20_ctx *ctx = crypto_tfm_ctx(tfm); + salsa20_keysetup(ctx, key, keysize); + return 0; +} + +static int encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct blkcipher_walk walk; + struct crypto_blkcipher *tfm = desc->tfm; + struct salsa20_ctx *ctx = crypto_blkcipher_ctx(tfm); + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt_block(desc, &walk, 64); + + salsa20_ivsetup(ctx, walk.iv); + + if (likely(walk.nbytes == nbytes)) + { + salsa20_encrypt_bytes(ctx, walk.dst.virt.addr, + walk.src.virt.addr, nbytes); + return blkcipher_walk_done(desc, &walk, 0); + } + + while (walk.nbytes >= 64) { + salsa20_encrypt_bytes(ctx, walk.dst.virt.addr, + walk.src.virt.addr, + walk.nbytes - (walk.nbytes % 64)); + err = blkcipher_walk_done(desc, &walk, walk.nbytes % 64); + } + + if (walk.nbytes) { + salsa20_encrypt_bytes(ctx, walk.dst.virt.addr, + walk.src.virt.addr, walk.nbytes); + err = blkcipher_walk_done(desc, &walk, 0); + } + + return err; +} + +static struct crypto_alg alg = { + .cra_name = "salsa20", + .cra_driver_name = "salsa20-generic", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_type = &crypto_blkcipher_type, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct salsa20_ctx), + .cra_alignmask = 3, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(alg.cra_list), + .cra_u = { + .blkcipher = { + .setkey = setkey, + .encrypt = encrypt, + .decrypt = encrypt, + .min_keysize = SALSA20_MIN_KEY_SIZE, + .max_keysize = SALSA20_MAX_KEY_SIZE, + .ivsize = SALSA20_IV_SIZE, + } + } +}; + +static int __init init(void) +{ + return crypto_register_alg(&alg); +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&alg); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION ("Salsa20 stream cipher algorithm"); +MODULE_ALIAS("salsa20"); diff --git a/crypto/scatterwalk.c b/crypto/scatterwalk.c index b9bbda0bb9f9..9aeeb52004a5 100644 --- a/crypto/scatterwalk.c +++ b/crypto/scatterwalk.c @@ -13,6 +13,8 @@ * any later version. * */ + +#include <crypto/scatterwalk.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/module.h> @@ -20,9 +22,6 @@ #include <linux/highmem.h> #include <linux/scatterlist.h> -#include "internal.h" -#include "scatterwalk.h" - static inline void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out) { void *src = out ? buf : sgdata; @@ -106,6 +105,9 @@ void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg, struct scatter_walk walk; unsigned int offset = 0; + if (!nbytes) + return; + for (;;) { scatterwalk_start(&walk, sg); @@ -113,7 +115,7 @@ void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg, break; offset += sg->length; - sg = sg_next(sg); + sg = scatterwalk_sg_next(sg); } scatterwalk_advance(&walk, start - offset); diff --git a/crypto/seqiv.c b/crypto/seqiv.c new file mode 100644 index 000000000000..b903aab31577 --- /dev/null +++ b/crypto/seqiv.c @@ -0,0 +1,345 @@ +/* + * seqiv: Sequence Number IV Generator + * + * This generator generates an IV based on a sequence number by xoring it + * with a salt. This algorithm is mainly useful for CTR and similar modes. + * + * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au> + * + * 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. + * + */ + +#include <crypto/internal/aead.h> +#include <crypto/internal/skcipher.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/random.h> +#include <linux/spinlock.h> +#include <linux/string.h> + +struct seqiv_ctx { + spinlock_t lock; + u8 salt[] __attribute__ ((aligned(__alignof__(u32)))); +}; + +static void seqiv_complete2(struct skcipher_givcrypt_request *req, int err) +{ + struct ablkcipher_request *subreq = skcipher_givcrypt_reqctx(req); + struct crypto_ablkcipher *geniv; + + if (err == -EINPROGRESS) + return; + + if (err) + goto out; + + geniv = skcipher_givcrypt_reqtfm(req); + memcpy(req->creq.info, subreq->info, crypto_ablkcipher_ivsize(geniv)); + +out: + kfree(subreq->info); +} + +static void seqiv_complete(struct crypto_async_request *base, int err) +{ + struct skcipher_givcrypt_request *req = base->data; + + seqiv_complete2(req, err); + skcipher_givcrypt_complete(req, err); +} + +static void seqiv_aead_complete2(struct aead_givcrypt_request *req, int err) +{ + struct aead_request *subreq = aead_givcrypt_reqctx(req); + struct crypto_aead *geniv; + + if (err == -EINPROGRESS) + return; + + if (err) + goto out; + + geniv = aead_givcrypt_reqtfm(req); + memcpy(req->areq.iv, subreq->iv, crypto_aead_ivsize(geniv)); + +out: + kfree(subreq->iv); +} + +static void seqiv_aead_complete(struct crypto_async_request *base, int err) +{ + struct aead_givcrypt_request *req = base->data; + + seqiv_aead_complete2(req, err); + aead_givcrypt_complete(req, err); +} + +static void seqiv_geniv(struct seqiv_ctx *ctx, u8 *info, u64 seq, + unsigned int ivsize) +{ + unsigned int len = ivsize; + + if (ivsize > sizeof(u64)) { + memset(info, 0, ivsize - sizeof(u64)); + len = sizeof(u64); + } + seq = cpu_to_be64(seq); + memcpy(info + ivsize - len, &seq, len); + crypto_xor(info, ctx->salt, ivsize); +} + +static int seqiv_givencrypt(struct skcipher_givcrypt_request *req) +{ + struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req); + struct seqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv); + struct ablkcipher_request *subreq = skcipher_givcrypt_reqctx(req); + crypto_completion_t complete; + void *data; + u8 *info; + unsigned int ivsize; + int err; + + ablkcipher_request_set_tfm(subreq, skcipher_geniv_cipher(geniv)); + + complete = req->creq.base.complete; + data = req->creq.base.data; + info = req->creq.info; + + ivsize = crypto_ablkcipher_ivsize(geniv); + + if (unlikely(!IS_ALIGNED((unsigned long)info, + crypto_ablkcipher_alignmask(geniv) + 1))) { + info = kmalloc(ivsize, req->creq.base.flags & + CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL: + GFP_ATOMIC); + if (!info) + return -ENOMEM; + + complete = seqiv_complete; + data = req; + } + + ablkcipher_request_set_callback(subreq, req->creq.base.flags, complete, + data); + ablkcipher_request_set_crypt(subreq, req->creq.src, req->creq.dst, + req->creq.nbytes, info); + + seqiv_geniv(ctx, info, req->seq, ivsize); + memcpy(req->giv, info, ivsize); + + err = crypto_ablkcipher_encrypt(subreq); + if (unlikely(info != req->creq.info)) + seqiv_complete2(req, err); + return err; +} + +static int seqiv_aead_givencrypt(struct aead_givcrypt_request *req) +{ + struct crypto_aead *geniv = aead_givcrypt_reqtfm(req); + struct seqiv_ctx *ctx = crypto_aead_ctx(geniv); + struct aead_request *areq = &req->areq; + struct aead_request *subreq = aead_givcrypt_reqctx(req); + crypto_completion_t complete; + void *data; + u8 *info; + unsigned int ivsize; + int err; + + aead_request_set_tfm(subreq, aead_geniv_base(geniv)); + + complete = areq->base.complete; + data = areq->base.data; + info = areq->iv; + + ivsize = crypto_aead_ivsize(geniv); + + if (unlikely(!IS_ALIGNED((unsigned long)info, + crypto_aead_alignmask(geniv) + 1))) { + info = kmalloc(ivsize, areq->base.flags & + CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL: + GFP_ATOMIC); + if (!info) + return -ENOMEM; + + complete = seqiv_aead_complete; + data = req; + } + + aead_request_set_callback(subreq, areq->base.flags, complete, data); + aead_request_set_crypt(subreq, areq->src, areq->dst, areq->cryptlen, + info); + aead_request_set_assoc(subreq, areq->assoc, areq->assoclen); + + seqiv_geniv(ctx, info, req->seq, ivsize); + memcpy(req->giv, info, ivsize); + + err = crypto_aead_encrypt(subreq); + if (unlikely(info != areq->iv)) + seqiv_aead_complete2(req, err); + return err; +} + +static int seqiv_givencrypt_first(struct skcipher_givcrypt_request *req) +{ + struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req); + struct seqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv); + + spin_lock_bh(&ctx->lock); + if (crypto_ablkcipher_crt(geniv)->givencrypt != seqiv_givencrypt_first) + goto unlock; + + crypto_ablkcipher_crt(geniv)->givencrypt = seqiv_givencrypt; + get_random_bytes(ctx->salt, crypto_ablkcipher_ivsize(geniv)); + +unlock: + spin_unlock_bh(&ctx->lock); + + return seqiv_givencrypt(req); +} + +static int seqiv_aead_givencrypt_first(struct aead_givcrypt_request *req) +{ + struct crypto_aead *geniv = aead_givcrypt_reqtfm(req); + struct seqiv_ctx *ctx = crypto_aead_ctx(geniv); + + spin_lock_bh(&ctx->lock); + if (crypto_aead_crt(geniv)->givencrypt != seqiv_aead_givencrypt_first) + goto unlock; + + crypto_aead_crt(geniv)->givencrypt = seqiv_aead_givencrypt; + get_random_bytes(ctx->salt, crypto_aead_ivsize(geniv)); + +unlock: + spin_unlock_bh(&ctx->lock); + + return seqiv_aead_givencrypt(req); +} + +static int seqiv_init(struct crypto_tfm *tfm) +{ + struct crypto_ablkcipher *geniv = __crypto_ablkcipher_cast(tfm); + struct seqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv); + + spin_lock_init(&ctx->lock); + + tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request); + + return skcipher_geniv_init(tfm); +} + +static int seqiv_aead_init(struct crypto_tfm *tfm) +{ + struct crypto_aead *geniv = __crypto_aead_cast(tfm); + struct seqiv_ctx *ctx = crypto_aead_ctx(geniv); + + spin_lock_init(&ctx->lock); + + tfm->crt_aead.reqsize = sizeof(struct aead_request); + + return aead_geniv_init(tfm); +} + +static struct crypto_template seqiv_tmpl; + +static struct crypto_instance *seqiv_ablkcipher_alloc(struct rtattr **tb) +{ + struct crypto_instance *inst; + + inst = skcipher_geniv_alloc(&seqiv_tmpl, tb, 0, 0); + + if (IS_ERR(inst)) + goto out; + + inst->alg.cra_ablkcipher.givencrypt = seqiv_givencrypt_first; + + inst->alg.cra_init = seqiv_init; + inst->alg.cra_exit = skcipher_geniv_exit; + + inst->alg.cra_ctxsize += inst->alg.cra_ablkcipher.ivsize; + +out: + return inst; +} + +static struct crypto_instance *seqiv_aead_alloc(struct rtattr **tb) +{ + struct crypto_instance *inst; + + inst = aead_geniv_alloc(&seqiv_tmpl, tb, 0, 0); + + if (IS_ERR(inst)) + goto out; + + inst->alg.cra_aead.givencrypt = seqiv_aead_givencrypt_first; + + inst->alg.cra_init = seqiv_aead_init; + inst->alg.cra_exit = aead_geniv_exit; + + inst->alg.cra_ctxsize = inst->alg.cra_aead.ivsize; + +out: + return inst; +} + +static struct crypto_instance *seqiv_alloc(struct rtattr **tb) +{ + struct crypto_attr_type *algt; + struct crypto_instance *inst; + int err; + + algt = crypto_get_attr_type(tb); + err = PTR_ERR(algt); + if (IS_ERR(algt)) + return ERR_PTR(err); + + if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & CRYPTO_ALG_TYPE_MASK) + inst = seqiv_ablkcipher_alloc(tb); + else + inst = seqiv_aead_alloc(tb); + + if (IS_ERR(inst)) + goto out; + + inst->alg.cra_alignmask |= __alignof__(u32) - 1; + inst->alg.cra_ctxsize += sizeof(struct seqiv_ctx); + +out: + return inst; +} + +static void seqiv_free(struct crypto_instance *inst) +{ + if ((inst->alg.cra_flags ^ CRYPTO_ALG_TYPE_AEAD) & CRYPTO_ALG_TYPE_MASK) + skcipher_geniv_free(inst); + else + aead_geniv_free(inst); +} + +static struct crypto_template seqiv_tmpl = { + .name = "seqiv", + .alloc = seqiv_alloc, + .free = seqiv_free, + .module = THIS_MODULE, +}; + +static int __init seqiv_module_init(void) +{ + return crypto_register_template(&seqiv_tmpl); +} + +static void __exit seqiv_module_exit(void) +{ + crypto_unregister_template(&seqiv_tmpl); +} + +module_init(seqiv_module_init); +module_exit(seqiv_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Sequence Number IV Generator"); diff --git a/crypto/sha256_generic.c b/crypto/sha256_generic.c index fd3918be58b5..3cc93fd61043 100644 --- a/crypto/sha256_generic.c +++ b/crypto/sha256_generic.c @@ -9,6 +9,7 @@ * Copyright (c) Jean-Luc Cooke <jlcooke@certainkey.com> * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk> * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> + * SHA224 Support Copyright 2007 Intel Corporation <jonathan.lynch@intel.com> * * 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 @@ -218,6 +219,22 @@ static void sha256_transform(u32 *state, const u8 *input) memset(W, 0, 64 * sizeof(u32)); } + +static void sha224_init(struct crypto_tfm *tfm) +{ + struct sha256_ctx *sctx = crypto_tfm_ctx(tfm); + sctx->state[0] = SHA224_H0; + sctx->state[1] = SHA224_H1; + sctx->state[2] = SHA224_H2; + sctx->state[3] = SHA224_H3; + sctx->state[4] = SHA224_H4; + sctx->state[5] = SHA224_H5; + sctx->state[6] = SHA224_H6; + sctx->state[7] = SHA224_H7; + sctx->count[0] = 0; + sctx->count[1] = 0; +} + static void sha256_init(struct crypto_tfm *tfm) { struct sha256_ctx *sctx = crypto_tfm_ctx(tfm); @@ -294,8 +311,17 @@ static void sha256_final(struct crypto_tfm *tfm, u8 *out) memset(sctx, 0, sizeof(*sctx)); } +static void sha224_final(struct crypto_tfm *tfm, u8 *hash) +{ + u8 D[SHA256_DIGEST_SIZE]; + + sha256_final(tfm, D); + + memcpy(hash, D, SHA224_DIGEST_SIZE); + memset(D, 0, SHA256_DIGEST_SIZE); +} -static struct crypto_alg alg = { +static struct crypto_alg sha256 = { .cra_name = "sha256", .cra_driver_name= "sha256-generic", .cra_flags = CRYPTO_ALG_TYPE_DIGEST, @@ -303,28 +329,58 @@ static struct crypto_alg alg = { .cra_ctxsize = sizeof(struct sha256_ctx), .cra_module = THIS_MODULE, .cra_alignmask = 3, - .cra_list = LIST_HEAD_INIT(alg.cra_list), + .cra_list = LIST_HEAD_INIT(sha256.cra_list), .cra_u = { .digest = { .dia_digestsize = SHA256_DIGEST_SIZE, - .dia_init = sha256_init, - .dia_update = sha256_update, - .dia_final = sha256_final } } + .dia_init = sha256_init, + .dia_update = sha256_update, + .dia_final = sha256_final } } +}; + +static struct crypto_alg sha224 = { + .cra_name = "sha224", + .cra_driver_name = "sha224-generic", + .cra_flags = CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize = SHA224_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct sha256_ctx), + .cra_module = THIS_MODULE, + .cra_alignmask = 3, + .cra_list = LIST_HEAD_INIT(sha224.cra_list), + .cra_u = { .digest = { + .dia_digestsize = SHA224_DIGEST_SIZE, + .dia_init = sha224_init, + .dia_update = sha256_update, + .dia_final = sha224_final } } }; static int __init init(void) { - return crypto_register_alg(&alg); + int ret = 0; + + ret = crypto_register_alg(&sha224); + + if (ret < 0) + return ret; + + ret = crypto_register_alg(&sha256); + + if (ret < 0) + crypto_unregister_alg(&sha224); + + return ret; } static void __exit fini(void) { - crypto_unregister_alg(&alg); + crypto_unregister_alg(&sha224); + crypto_unregister_alg(&sha256); } module_init(init); module_exit(fini); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("SHA256 Secure Hash Algorithm"); +MODULE_DESCRIPTION("SHA-224 and SHA-256 Secure Hash Algorithm"); +MODULE_ALIAS("sha224"); MODULE_ALIAS("sha256"); diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index 24141fb6f5cb..1ab8c017a011 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -6,12 +6,16 @@ * * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> * Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org> + * Copyright (c) 2007 Nokia Siemens Networks * * 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. * + * 2007-11-13 Added GCM tests + * 2007-11-13 Added AEAD support + * 2007-11-06 Added SHA-224 and SHA-224-HMAC tests * 2006-12-07 Added SHA384 HMAC and SHA512 HMAC tests * 2004-08-09 Added cipher speed tests (Reyk Floeter <reyk@vantronix.net>) * 2003-09-14 Rewritten by Kartikey Mahendra Bhatt @@ -71,22 +75,23 @@ static unsigned int sec; static int mode; static char *xbuf; +static char *axbuf; static char *tvmem; static char *check[] = { - "des", "md5", "des3_ede", "rot13", "sha1", "sha256", "blowfish", - "twofish", "serpent", "sha384", "sha512", "md4", "aes", "cast6", + "des", "md5", "des3_ede", "rot13", "sha1", "sha224", "sha256", + "blowfish", "twofish", "serpent", "sha384", "sha512", "md4", "aes", + "cast6", "arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea", "arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea", "khazad", "wp512", "wp384", "wp256", "tnepres", "xeta", "fcrypt", - "camellia", "seed", NULL + "camellia", "seed", "salsa20", "lzo", NULL }; static void hexdump(unsigned char *buf, unsigned int len) { - while (len--) - printk("%02x", *buf++); - - printk("\n"); + print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET, + 16, 1, + buf, len, false); } static void tcrypt_complete(struct crypto_async_request *req, int err) @@ -215,6 +220,238 @@ out: crypto_free_hash(tfm); } +static void test_aead(char *algo, int enc, struct aead_testvec *template, + unsigned int tcount) +{ + unsigned int ret, i, j, k, temp; + unsigned int tsize; + char *q; + struct crypto_aead *tfm; + char *key; + struct aead_testvec *aead_tv; + struct aead_request *req; + struct scatterlist sg[8]; + struct scatterlist asg[8]; + const char *e; + struct tcrypt_result result; + unsigned int authsize; + + if (enc == ENCRYPT) + e = "encryption"; + else + e = "decryption"; + + printk(KERN_INFO "\ntesting %s %s\n", algo, e); + + tsize = sizeof(struct aead_testvec); + tsize *= tcount; + + if (tsize > TVMEMSIZE) { + printk(KERN_INFO "template (%u) too big for tvmem (%u)\n", + tsize, TVMEMSIZE); + return; + } + + memcpy(tvmem, template, tsize); + aead_tv = (void *)tvmem; + + init_completion(&result.completion); + + tfm = crypto_alloc_aead(algo, 0, 0); + + if (IS_ERR(tfm)) { + printk(KERN_INFO "failed to load transform for %s: %ld\n", + algo, PTR_ERR(tfm)); + return; + } + + req = aead_request_alloc(tfm, GFP_KERNEL); + if (!req) { + printk(KERN_INFO "failed to allocate request for %s\n", algo); + goto out; + } + + aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + tcrypt_complete, &result); + + for (i = 0, j = 0; i < tcount; i++) { + if (!aead_tv[i].np) { + printk(KERN_INFO "test %u (%d bit key):\n", + ++j, aead_tv[i].klen * 8); + + crypto_aead_clear_flags(tfm, ~0); + if (aead_tv[i].wk) + crypto_aead_set_flags( + tfm, CRYPTO_TFM_REQ_WEAK_KEY); + key = aead_tv[i].key; + + ret = crypto_aead_setkey(tfm, key, + aead_tv[i].klen); + if (ret) { + printk(KERN_INFO "setkey() failed flags=%x\n", + crypto_aead_get_flags(tfm)); + + if (!aead_tv[i].fail) + goto out; + } + + authsize = abs(aead_tv[i].rlen - aead_tv[i].ilen); + ret = crypto_aead_setauthsize(tfm, authsize); + if (ret) { + printk(KERN_INFO + "failed to set authsize = %u\n", + authsize); + goto out; + } + + sg_init_one(&sg[0], aead_tv[i].input, + aead_tv[i].ilen + (enc ? authsize : 0)); + + sg_init_one(&asg[0], aead_tv[i].assoc, + aead_tv[i].alen); + + aead_request_set_crypt(req, sg, sg, + aead_tv[i].ilen, + aead_tv[i].iv); + + aead_request_set_assoc(req, asg, aead_tv[i].alen); + + ret = enc ? + crypto_aead_encrypt(req) : + crypto_aead_decrypt(req); + + switch (ret) { + case 0: + break; + case -EINPROGRESS: + case -EBUSY: + ret = wait_for_completion_interruptible( + &result.completion); + if (!ret && !(ret = result.err)) { + INIT_COMPLETION(result.completion); + break; + } + /* fall through */ + default: + printk(KERN_INFO "%s () failed err=%d\n", + e, -ret); + goto out; + } + + q = kmap(sg_page(&sg[0])) + sg[0].offset; + hexdump(q, aead_tv[i].rlen); + + printk(KERN_INFO "enc/dec: %s\n", + memcmp(q, aead_tv[i].result, + aead_tv[i].rlen) ? "fail" : "pass"); + } + } + + printk(KERN_INFO "\ntesting %s %s across pages (chunking)\n", algo, e); + memset(xbuf, 0, XBUFSIZE); + memset(axbuf, 0, XBUFSIZE); + + for (i = 0, j = 0; i < tcount; i++) { + if (aead_tv[i].np) { + printk(KERN_INFO "test %u (%d bit key):\n", + ++j, aead_tv[i].klen * 8); + + crypto_aead_clear_flags(tfm, ~0); + if (aead_tv[i].wk) + crypto_aead_set_flags( + tfm, CRYPTO_TFM_REQ_WEAK_KEY); + key = aead_tv[i].key; + + ret = crypto_aead_setkey(tfm, key, aead_tv[i].klen); + if (ret) { + printk(KERN_INFO "setkey() failed flags=%x\n", + crypto_aead_get_flags(tfm)); + + if (!aead_tv[i].fail) + goto out; + } + + sg_init_table(sg, aead_tv[i].np); + for (k = 0, temp = 0; k < aead_tv[i].np; k++) { + memcpy(&xbuf[IDX[k]], + aead_tv[i].input + temp, + aead_tv[i].tap[k]); + temp += aead_tv[i].tap[k]; + sg_set_buf(&sg[k], &xbuf[IDX[k]], + aead_tv[i].tap[k]); + } + + authsize = abs(aead_tv[i].rlen - aead_tv[i].ilen); + ret = crypto_aead_setauthsize(tfm, authsize); + if (ret) { + printk(KERN_INFO + "failed to set authsize = %u\n", + authsize); + goto out; + } + + if (enc) + sg[k - 1].length += authsize; + + sg_init_table(asg, aead_tv[i].anp); + for (k = 0, temp = 0; k < aead_tv[i].anp; k++) { + memcpy(&axbuf[IDX[k]], + aead_tv[i].assoc + temp, + aead_tv[i].atap[k]); + temp += aead_tv[i].atap[k]; + sg_set_buf(&asg[k], &axbuf[IDX[k]], + aead_tv[i].atap[k]); + } + + aead_request_set_crypt(req, sg, sg, + aead_tv[i].ilen, + aead_tv[i].iv); + + aead_request_set_assoc(req, asg, aead_tv[i].alen); + + ret = enc ? + crypto_aead_encrypt(req) : + crypto_aead_decrypt(req); + + switch (ret) { + case 0: + break; + case -EINPROGRESS: + case -EBUSY: + ret = wait_for_completion_interruptible( + &result.completion); + if (!ret && !(ret = result.err)) { + INIT_COMPLETION(result.completion); + break; + } + /* fall through */ + default: + printk(KERN_INFO "%s () failed err=%d\n", + e, -ret); + goto out; + } + + for (k = 0, temp = 0; k < aead_tv[i].np; k++) { + printk(KERN_INFO "page %u\n", k); + q = kmap(sg_page(&sg[k])) + sg[k].offset; + hexdump(q, aead_tv[i].tap[k]); + printk(KERN_INFO "%s\n", + memcmp(q, aead_tv[i].result + temp, + aead_tv[i].tap[k] - + (k < aead_tv[i].np - 1 || enc ? + 0 : authsize)) ? + "fail" : "pass"); + + temp += aead_tv[i].tap[k]; + } + } + } + +out: + crypto_free_aead(tfm); + aead_request_free(req); +} + static void test_cipher(char *algo, int enc, struct cipher_testvec *template, unsigned int tcount) { @@ -237,15 +474,11 @@ static void test_cipher(char *algo, int enc, printk("\ntesting %s %s\n", algo, e); tsize = sizeof (struct cipher_testvec); - tsize *= tcount; - if (tsize > TVMEMSIZE) { printk("template (%u) too big for tvmem (%u)\n", tsize, TVMEMSIZE); return; } - - memcpy(tvmem, template, tsize); cipher_tv = (void *)tvmem; init_completion(&result.completion); @@ -269,33 +502,34 @@ static void test_cipher(char *algo, int enc, j = 0; for (i = 0; i < tcount; i++) { - if (!(cipher_tv[i].np)) { + memcpy(cipher_tv, &template[i], tsize); + if (!(cipher_tv->np)) { j++; printk("test %u (%d bit key):\n", - j, cipher_tv[i].klen * 8); + j, cipher_tv->klen * 8); crypto_ablkcipher_clear_flags(tfm, ~0); - if (cipher_tv[i].wk) + if (cipher_tv->wk) crypto_ablkcipher_set_flags( tfm, CRYPTO_TFM_REQ_WEAK_KEY); - key = cipher_tv[i].key; + key = cipher_tv->key; ret = crypto_ablkcipher_setkey(tfm, key, - cipher_tv[i].klen); + cipher_tv->klen); if (ret) { printk("setkey() failed flags=%x\n", crypto_ablkcipher_get_flags(tfm)); - if (!cipher_tv[i].fail) + if (!cipher_tv->fail) goto out; } - sg_init_one(&sg[0], cipher_tv[i].input, - cipher_tv[i].ilen); + sg_init_one(&sg[0], cipher_tv->input, + cipher_tv->ilen); ablkcipher_request_set_crypt(req, sg, sg, - cipher_tv[i].ilen, - cipher_tv[i].iv); + cipher_tv->ilen, + cipher_tv->iv); ret = enc ? crypto_ablkcipher_encrypt(req) : @@ -319,11 +553,11 @@ static void test_cipher(char *algo, int enc, } q = kmap(sg_page(&sg[0])) + sg[0].offset; - hexdump(q, cipher_tv[i].rlen); + hexdump(q, cipher_tv->rlen); printk("%s\n", - memcmp(q, cipher_tv[i].result, - cipher_tv[i].rlen) ? "fail" : "pass"); + memcmp(q, cipher_tv->result, + cipher_tv->rlen) ? "fail" : "pass"); } } @@ -332,41 +566,42 @@ static void test_cipher(char *algo, int enc, j = 0; for (i = 0; i < tcount; i++) { - if (cipher_tv[i].np) { + memcpy(cipher_tv, &template[i], tsize); + if (cipher_tv->np) { j++; printk("test %u (%d bit key):\n", - j, cipher_tv[i].klen * 8); + j, cipher_tv->klen * 8); crypto_ablkcipher_clear_flags(tfm, ~0); - if (cipher_tv[i].wk) + if (cipher_tv->wk) crypto_ablkcipher_set_flags( tfm, CRYPTO_TFM_REQ_WEAK_KEY); - key = cipher_tv[i].key; + key = cipher_tv->key; ret = crypto_ablkcipher_setkey(tfm, key, - cipher_tv[i].klen); + cipher_tv->klen); if (ret) { printk("setkey() failed flags=%x\n", crypto_ablkcipher_get_flags(tfm)); - if (!cipher_tv[i].fail) + if (!cipher_tv->fail) goto out; } temp = 0; - sg_init_table(sg, cipher_tv[i].np); - for (k = 0; k < cipher_tv[i].np; k++) { + sg_init_table(sg, cipher_tv->np); + for (k = 0; k < cipher_tv->np; k++) { memcpy(&xbuf[IDX[k]], - cipher_tv[i].input + temp, - cipher_tv[i].tap[k]); - temp += cipher_tv[i].tap[k]; + cipher_tv->input + temp, + cipher_tv->tap[k]); + temp += cipher_tv->tap[k]; sg_set_buf(&sg[k], &xbuf[IDX[k]], - cipher_tv[i].tap[k]); + cipher_tv->tap[k]); } ablkcipher_request_set_crypt(req, sg, sg, - cipher_tv[i].ilen, - cipher_tv[i].iv); + cipher_tv->ilen, + cipher_tv->iv); ret = enc ? crypto_ablkcipher_encrypt(req) : @@ -390,15 +625,15 @@ static void test_cipher(char *algo, int enc, } temp = 0; - for (k = 0; k < cipher_tv[i].np; k++) { + for (k = 0; k < cipher_tv->np; k++) { printk("page %u\n", k); q = kmap(sg_page(&sg[k])) + sg[k].offset; - hexdump(q, cipher_tv[i].tap[k]); + hexdump(q, cipher_tv->tap[k]); printk("%s\n", - memcmp(q, cipher_tv[i].result + temp, - cipher_tv[i].tap[k]) ? "fail" : + memcmp(q, cipher_tv->result + temp, + cipher_tv->tap[k]) ? "fail" : "pass"); - temp += cipher_tv[i].tap[k]; + temp += cipher_tv->tap[k]; } } } @@ -800,7 +1035,8 @@ out: crypto_free_hash(tfm); } -static void test_deflate(void) +static void test_comp(char *algo, struct comp_testvec *ctemplate, + struct comp_testvec *dtemplate, int ctcount, int dtcount) { unsigned int i; char result[COMP_BUF_SIZE]; @@ -808,25 +1044,26 @@ static void test_deflate(void) struct comp_testvec *tv; unsigned int tsize; - printk("\ntesting deflate compression\n"); + printk("\ntesting %s compression\n", algo); - tsize = sizeof (deflate_comp_tv_template); + tsize = sizeof(struct comp_testvec); + tsize *= ctcount; if (tsize > TVMEMSIZE) { printk("template (%u) too big for tvmem (%u)\n", tsize, TVMEMSIZE); return; } - memcpy(tvmem, deflate_comp_tv_template, tsize); + memcpy(tvmem, ctemplate, tsize); tv = (void *)tvmem; - tfm = crypto_alloc_comp("deflate", 0, CRYPTO_ALG_ASYNC); + tfm = crypto_alloc_comp(algo, 0, CRYPTO_ALG_ASYNC); if (IS_ERR(tfm)) { - printk("failed to load transform for deflate\n"); + printk("failed to load transform for %s\n", algo); return; } - for (i = 0; i < DEFLATE_COMP_TEST_VECTORS; i++) { + for (i = 0; i < ctcount; i++) { int ilen, ret, dlen = COMP_BUF_SIZE; printk("test %u:\n", i + 1); @@ -845,19 +1082,20 @@ static void test_deflate(void) ilen, dlen); } - printk("\ntesting deflate decompression\n"); + printk("\ntesting %s decompression\n", algo); - tsize = sizeof (deflate_decomp_tv_template); + tsize = sizeof(struct comp_testvec); + tsize *= dtcount; if (tsize > TVMEMSIZE) { printk("template (%u) too big for tvmem (%u)\n", tsize, TVMEMSIZE); goto out; } - memcpy(tvmem, deflate_decomp_tv_template, tsize); + memcpy(tvmem, dtemplate, tsize); tv = (void *)tvmem; - for (i = 0; i < DEFLATE_DECOMP_TEST_VECTORS; i++) { + for (i = 0; i < dtcount; i++) { int ilen, ret, dlen = COMP_BUF_SIZE; printk("test %u:\n", i + 1); @@ -918,6 +1156,8 @@ static void do_test(void) test_hash("md4", md4_tv_template, MD4_TEST_VECTORS); + test_hash("sha224", sha224_tv_template, SHA224_TEST_VECTORS); + test_hash("sha256", sha256_tv_template, SHA256_TEST_VECTORS); //BLOWFISH @@ -969,6 +1209,18 @@ static void do_test(void) AES_XTS_ENC_TEST_VECTORS); test_cipher("xts(aes)", DECRYPT, aes_xts_dec_tv_template, AES_XTS_DEC_TEST_VECTORS); + test_cipher("rfc3686(ctr(aes))", ENCRYPT, aes_ctr_enc_tv_template, + AES_CTR_ENC_TEST_VECTORS); + test_cipher("rfc3686(ctr(aes))", DECRYPT, aes_ctr_dec_tv_template, + AES_CTR_DEC_TEST_VECTORS); + test_aead("gcm(aes)", ENCRYPT, aes_gcm_enc_tv_template, + AES_GCM_ENC_TEST_VECTORS); + test_aead("gcm(aes)", DECRYPT, aes_gcm_dec_tv_template, + AES_GCM_DEC_TEST_VECTORS); + test_aead("ccm(aes)", ENCRYPT, aes_ccm_enc_tv_template, + AES_CCM_ENC_TEST_VECTORS); + test_aead("ccm(aes)", DECRYPT, aes_ccm_dec_tv_template, + AES_CCM_DEC_TEST_VECTORS); //CAST5 test_cipher("ecb(cast5)", ENCRYPT, cast5_enc_tv_template, @@ -1057,12 +1309,18 @@ static void do_test(void) test_hash("tgr192", tgr192_tv_template, TGR192_TEST_VECTORS); test_hash("tgr160", tgr160_tv_template, TGR160_TEST_VECTORS); test_hash("tgr128", tgr128_tv_template, TGR128_TEST_VECTORS); - test_deflate(); + test_comp("deflate", deflate_comp_tv_template, + deflate_decomp_tv_template, DEFLATE_COMP_TEST_VECTORS, + DEFLATE_DECOMP_TEST_VECTORS); + test_comp("lzo", lzo_comp_tv_template, lzo_decomp_tv_template, + LZO_COMP_TEST_VECTORS, LZO_DECOMP_TEST_VECTORS); test_hash("crc32c", crc32c_tv_template, CRC32C_TEST_VECTORS); test_hash("hmac(md5)", hmac_md5_tv_template, HMAC_MD5_TEST_VECTORS); test_hash("hmac(sha1)", hmac_sha1_tv_template, HMAC_SHA1_TEST_VECTORS); + test_hash("hmac(sha224)", hmac_sha224_tv_template, + HMAC_SHA224_TEST_VECTORS); test_hash("hmac(sha256)", hmac_sha256_tv_template, HMAC_SHA256_TEST_VECTORS); test_hash("hmac(sha384)", hmac_sha384_tv_template, @@ -1156,6 +1414,10 @@ static void do_test(void) AES_XTS_ENC_TEST_VECTORS); test_cipher("xts(aes)", DECRYPT, aes_xts_dec_tv_template, AES_XTS_DEC_TEST_VECTORS); + test_cipher("rfc3686(ctr(aes))", ENCRYPT, aes_ctr_enc_tv_template, + AES_CTR_ENC_TEST_VECTORS); + test_cipher("rfc3686(ctr(aes))", DECRYPT, aes_ctr_dec_tv_template, + AES_CTR_DEC_TEST_VECTORS); break; case 11: @@ -1167,7 +1429,9 @@ static void do_test(void) break; case 13: - test_deflate(); + test_comp("deflate", deflate_comp_tv_template, + deflate_decomp_tv_template, DEFLATE_COMP_TEST_VECTORS, + DEFLATE_DECOMP_TEST_VECTORS); break; case 14: @@ -1291,6 +1555,34 @@ static void do_test(void) camellia_cbc_dec_tv_template, CAMELLIA_CBC_DEC_TEST_VECTORS); break; + case 33: + test_hash("sha224", sha224_tv_template, SHA224_TEST_VECTORS); + break; + + case 34: + test_cipher("salsa20", ENCRYPT, + salsa20_stream_enc_tv_template, + SALSA20_STREAM_ENC_TEST_VECTORS); + break; + + case 35: + test_aead("gcm(aes)", ENCRYPT, aes_gcm_enc_tv_template, + AES_GCM_ENC_TEST_VECTORS); + test_aead("gcm(aes)", DECRYPT, aes_gcm_dec_tv_template, + AES_GCM_DEC_TEST_VECTORS); + break; + + case 36: + test_comp("lzo", lzo_comp_tv_template, lzo_decomp_tv_template, + LZO_COMP_TEST_VECTORS, LZO_DECOMP_TEST_VECTORS); + break; + + case 37: + test_aead("ccm(aes)", ENCRYPT, aes_ccm_enc_tv_template, + AES_CCM_ENC_TEST_VECTORS); + test_aead("ccm(aes)", DECRYPT, aes_ccm_dec_tv_template, + AES_CCM_DEC_TEST_VECTORS); + break; case 100: test_hash("hmac(md5)", hmac_md5_tv_template, @@ -1317,6 +1609,15 @@ static void do_test(void) HMAC_SHA512_TEST_VECTORS); break; + case 105: + test_hash("hmac(sha224)", hmac_sha224_tv_template, + HMAC_SHA224_TEST_VECTORS); + break; + + case 106: + test_hash("xcbc(aes)", aes_xcbc128_tv_template, + XCBC_AES_TEST_VECTORS); + break; case 200: test_cipher_speed("ecb(aes)", ENCRYPT, sec, NULL, 0, @@ -1400,6 +1701,11 @@ static void do_test(void) camellia_speed_template); break; + case 206: + test_cipher_speed("salsa20", ENCRYPT, sec, NULL, 0, + salsa20_speed_template); + break; + case 300: /* fall through */ @@ -1451,6 +1757,10 @@ static void do_test(void) test_hash_speed("tgr192", sec, generic_hash_speed_template); if (mode > 300 && mode < 400) break; + case 313: + test_hash_speed("sha224", sec, generic_hash_speed_template); + if (mode > 300 && mode < 400) break; + case 399: break; @@ -1467,20 +1777,21 @@ static void do_test(void) static int __init init(void) { + int err = -ENOMEM; + tvmem = kmalloc(TVMEMSIZE, GFP_KERNEL); if (tvmem == NULL) - return -ENOMEM; + return err; xbuf = kmalloc(XBUFSIZE, GFP_KERNEL); - if (xbuf == NULL) { - kfree(tvmem); - return -ENOMEM; - } + if (xbuf == NULL) + goto err_free_tv; - do_test(); + axbuf = kmalloc(XBUFSIZE, GFP_KERNEL); + if (axbuf == NULL) + goto err_free_xbuf; - kfree(xbuf); - kfree(tvmem); + do_test(); /* We intentionaly return -EAGAIN to prevent keeping * the module. It does all its work from init() @@ -1488,7 +1799,15 @@ static int __init init(void) * => we don't need it in the memory, do we? * -- mludvig */ - return -EAGAIN; + err = -EAGAIN; + + kfree(axbuf); + err_free_xbuf: + kfree(xbuf); + err_free_tv: + kfree(tvmem); + + return err; } /* diff --git a/crypto/tcrypt.h b/crypto/tcrypt.h index ec861388d9a0..f785e5618e11 100644 --- a/crypto/tcrypt.h +++ b/crypto/tcrypt.h @@ -6,12 +6,15 @@ * * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> * Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org> + * Copyright (c) 2007 Nokia Siemens Networks * * 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. * + * 2007-11-13 Added GCM tests + * 2007-11-13 Added AEAD support * 2006-12-07 Added SHA384 HMAC and SHA512 HMAC tests * 2004-08-09 Cipher speed tests by Reyk Floeter <reyk@vantronix.net> * 2003-09-14 Changes by Kartikey Mahendra Bhatt @@ -40,14 +43,32 @@ struct hash_testvec { struct cipher_testvec { char key[MAX_KEYLEN] __attribute__ ((__aligned__(4))); char iv[MAX_IVLEN]; + char input[4100]; + char result[4100]; + unsigned char tap[MAX_TAP]; + int np; + unsigned char fail; + unsigned char wk; /* weak key flag */ + unsigned char klen; + unsigned short ilen; + unsigned short rlen; +}; + +struct aead_testvec { + char key[MAX_KEYLEN] __attribute__ ((__aligned__(4))); + char iv[MAX_IVLEN]; char input[512]; + char assoc[512]; char result[512]; unsigned char tap[MAX_TAP]; + unsigned char atap[MAX_TAP]; int np; + int anp; unsigned char fail; unsigned char wk; /* weak key flag */ unsigned char klen; unsigned short ilen; + unsigned short alen; unsigned short rlen; }; @@ -173,6 +194,33 @@ static struct hash_testvec sha1_tv_template[] = { } }; + +/* + * SHA224 test vectors from from FIPS PUB 180-2 + */ +#define SHA224_TEST_VECTORS 2 + +static struct hash_testvec sha224_tv_template[] = { + { + .plaintext = "abc", + .psize = 3, + .digest = { 0x23, 0x09, 0x7D, 0x22, 0x34, 0x05, 0xD8, 0x22, + 0x86, 0x42, 0xA4, 0x77, 0xBD, 0xA2, 0x55, 0xB3, + 0x2A, 0xAD, 0xBC, 0xE4, 0xBD, 0xA0, 0xB3, 0xF7, + 0xE3, 0x6C, 0x9D, 0xA7}, + }, { + .plaintext = + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + .psize = 56, + .digest = { 0x75, 0x38, 0x8B, 0x16, 0x51, 0x27, 0x76, 0xCC, + 0x5D, 0xBA, 0x5D, 0xA1, 0xFD, 0x89, 0x01, 0x50, + 0xB0, 0xC6, 0x45, 0x5C, 0xB4, 0xF5, 0x8B, 0x19, + 0x52, 0x52, 0x25, 0x25 }, + .np = 2, + .tap = { 28, 28 } + } +}; + /* * SHA256 test vectors from from NIST */ @@ -817,6 +865,121 @@ static struct hash_testvec hmac_sha1_tv_template[] = { }, }; + +/* + * SHA224 HMAC test vectors from RFC4231 + */ +#define HMAC_SHA224_TEST_VECTORS 4 + +static struct hash_testvec hmac_sha224_tv_template[] = { + { + .key = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b }, + .ksize = 20, + /* ("Hi There") */ + .plaintext = { 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65 }, + .psize = 8, + .digest = { 0x89, 0x6f, 0xb1, 0x12, 0x8a, 0xbb, 0xdf, 0x19, + 0x68, 0x32, 0x10, 0x7c, 0xd4, 0x9d, 0xf3, 0x3f, + 0x47, 0xb4, 0xb1, 0x16, 0x99, 0x12, 0xba, 0x4f, + 0x53, 0x68, 0x4b, 0x22}, + }, { + .key = { 0x4a, 0x65, 0x66, 0x65 }, /* ("Jefe") */ + .ksize = 4, + /* ("what do ya want for nothing?") */ + .plaintext = { 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20, + 0x79, 0x61, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20, + 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68, + 0x69, 0x6e, 0x67, 0x3f }, + .psize = 28, + .digest = { 0xa3, 0x0e, 0x01, 0x09, 0x8b, 0xc6, 0xdb, 0xbf, + 0x45, 0x69, 0x0f, 0x3a, 0x7e, 0x9e, 0x6d, 0x0f, + 0x8b, 0xbe, 0xa2, 0xa3, 0x9e, 0x61, 0x48, 0x00, + 0x8f, 0xd0, 0x5e, 0x44 }, + .np = 4, + .tap = { 7, 7, 7, 7 } + }, { + .key = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa }, + .ksize = 131, + /* ("Test Using Larger Than Block-Size Key - Hash Key First") */ + .plaintext = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69, + 0x6e, 0x67, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65, + 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, + 0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x2d, 0x20, + 0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79, + 0x20, 0x46, 0x69, 0x72, 0x73, 0x74 }, + .psize = 54, + .digest = { 0x95, 0xe9, 0xa0, 0xdb, 0x96, 0x20, 0x95, 0xad, + 0xae, 0xbe, 0x9b, 0x2d, 0x6f, 0x0d, 0xbc, 0xe2, + 0xd4, 0x99, 0xf1, 0x12, 0xf2, 0xd2, 0xb7, 0x27, + 0x3f, 0xa6, 0x87, 0x0e }, + }, { + .key = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa }, + .ksize = 131, + /* ("This is a test using a larger than block-size key and a") + (" larger than block-size data. The key needs to be") + (" hashed before being used by the HMAC algorithm.") */ + .plaintext = { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, + 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x75, + 0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x6c, + 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68, + 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6b, 0x65, + 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20, + 0x6c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, + 0x68, 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x64, + 0x61, 0x74, 0x61, 0x2e, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x6b, 0x65, 0x79, 0x20, 0x6e, 0x65, 0x65, + 0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, + 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x64, 0x20, + 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x62, + 0x65, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x73, 0x65, + 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x48, 0x4d, 0x41, 0x43, 0x20, 0x61, 0x6c, + 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x2e }, + .psize = 152, + .digest = { 0x3a, 0x85, 0x41, 0x66, 0xac, 0x5d, 0x9f, 0x02, + 0x3f, 0x54, 0xd5, 0x17, 0xd0, 0xb3, 0x9d, 0xbd, + 0x94, 0x67, 0x70, 0xdb, 0x9c, 0x2b, 0x95, 0xc9, + 0xf6, 0xf5, 0x65, 0xd1 }, + }, +}; + /* * HMAC-SHA256 test vectors from * draft-ietf-ipsec-ciph-sha-256-01.txt @@ -2140,12 +2303,18 @@ static struct cipher_testvec cast6_dec_tv_template[] = { */ #define AES_ENC_TEST_VECTORS 3 #define AES_DEC_TEST_VECTORS 3 -#define AES_CBC_ENC_TEST_VECTORS 2 -#define AES_CBC_DEC_TEST_VECTORS 2 +#define AES_CBC_ENC_TEST_VECTORS 4 +#define AES_CBC_DEC_TEST_VECTORS 4 #define AES_LRW_ENC_TEST_VECTORS 8 #define AES_LRW_DEC_TEST_VECTORS 8 #define AES_XTS_ENC_TEST_VECTORS 4 #define AES_XTS_DEC_TEST_VECTORS 4 +#define AES_CTR_ENC_TEST_VECTORS 7 +#define AES_CTR_DEC_TEST_VECTORS 6 +#define AES_GCM_ENC_TEST_VECTORS 9 +#define AES_GCM_DEC_TEST_VECTORS 8 +#define AES_CCM_ENC_TEST_VECTORS 7 +#define AES_CCM_DEC_TEST_VECTORS 7 static struct cipher_testvec aes_enc_tv_template[] = { { /* From FIPS-197 */ @@ -2249,6 +2418,57 @@ static struct cipher_testvec aes_cbc_enc_tv_template[] = { 0x75, 0x86, 0x60, 0x2d, 0x25, 0x3c, 0xff, 0xf9, 0x1b, 0x82, 0x66, 0xbe, 0xa6, 0xd6, 0x1a, 0xb1 }, .rlen = 32, + }, { /* From NIST SP800-38A */ + .key = { 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, + 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, + 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b }, + .klen = 24, + .iv = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + .input = { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 }, + .ilen = 64, + .result = { 0x4f, 0x02, 0x1d, 0xb2, 0x43, 0xbc, 0x63, 0x3d, + 0x71, 0x78, 0x18, 0x3a, 0x9f, 0xa0, 0x71, 0xe8, + 0xb4, 0xd9, 0xad, 0xa9, 0xad, 0x7d, 0xed, 0xf4, + 0xe5, 0xe7, 0x38, 0x76, 0x3f, 0x69, 0x14, 0x5a, + 0x57, 0x1b, 0x24, 0x20, 0x12, 0xfb, 0x7a, 0xe0, + 0x7f, 0xa9, 0xba, 0xac, 0x3d, 0xf1, 0x02, 0xe0, + 0x08, 0xb0, 0xe2, 0x79, 0x88, 0x59, 0x88, 0x81, + 0xd9, 0x20, 0xa9, 0xe6, 0x4f, 0x56, 0x15, 0xcd }, + .rlen = 64, + }, { + .key = { 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, + 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, + 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, + 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 }, + .klen = 32, + .iv = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + .input = { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 }, + .ilen = 64, + .result = { 0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, + 0x77, 0x9e, 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6, + 0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d, + 0x67, 0x9f, 0x77, 0x7b, 0xc6, 0x70, 0x2c, 0x7d, + 0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf, + 0xa5, 0x30, 0xe2, 0x63, 0x04, 0x23, 0x14, 0x61, + 0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc, + 0xda, 0x6c, 0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b }, + .rlen = 64, }, }; @@ -2280,6 +2500,57 @@ static struct cipher_testvec aes_cbc_dec_tv_template[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }, .rlen = 32, + }, { /* From NIST SP800-38A */ + .key = { 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, + 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, + 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b }, + .klen = 24, + .iv = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + .input = { 0x4f, 0x02, 0x1d, 0xb2, 0x43, 0xbc, 0x63, 0x3d, + 0x71, 0x78, 0x18, 0x3a, 0x9f, 0xa0, 0x71, 0xe8, + 0xb4, 0xd9, 0xad, 0xa9, 0xad, 0x7d, 0xed, 0xf4, + 0xe5, 0xe7, 0x38, 0x76, 0x3f, 0x69, 0x14, 0x5a, + 0x57, 0x1b, 0x24, 0x20, 0x12, 0xfb, 0x7a, 0xe0, + 0x7f, 0xa9, 0xba, 0xac, 0x3d, 0xf1, 0x02, 0xe0, + 0x08, 0xb0, 0xe2, 0x79, 0x88, 0x59, 0x88, 0x81, + 0xd9, 0x20, 0xa9, 0xe6, 0x4f, 0x56, 0x15, 0xcd }, + .ilen = 64, + .result = { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 }, + .rlen = 64, + }, { + .key = { 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, + 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, + 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, + 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 }, + .klen = 32, + .iv = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + .input = { 0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, + 0x77, 0x9e, 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6, + 0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d, + 0x67, 0x9f, 0x77, 0x7b, 0xc6, 0x70, 0x2c, 0x7d, + 0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf, + 0xa5, 0x30, 0xe2, 0x63, 0x04, 0x23, 0x14, 0x61, + 0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc, + 0xda, 0x6c, 0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b }, + .ilen = 64, + .result = { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 }, + .rlen = 64, }, }; @@ -3180,6 +3451,1843 @@ static struct cipher_testvec aes_xts_dec_tv_template[] = { } }; + +static struct cipher_testvec aes_ctr_enc_tv_template[] = { + { /* From RFC 3686 */ + .key = { 0xae, 0x68, 0x52, 0xf8, 0x12, 0x10, 0x67, 0xcc, + 0x4b, 0xf7, 0xa5, 0x76, 0x55, 0x77, 0xf3, 0x9e, + 0x00, 0x00, 0x00, 0x30 }, + .klen = 20, + .iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .input = { "Single block msg" }, + .ilen = 16, + .result = { 0xe4, 0x09, 0x5d, 0x4f, 0xb7, 0xa7, 0xb3, 0x79, + 0x2d, 0x61, 0x75, 0xa3, 0x26, 0x13, 0x11, 0xb8 }, + .rlen = 16, + }, { + .key = { 0x7e, 0x24, 0x06, 0x78, 0x17, 0xfa, 0xe0, 0xd7, + 0x43, 0xd6, 0xce, 0x1f, 0x32, 0x53, 0x91, 0x63, + 0x00, 0x6c, 0xb6, 0xdb }, + .klen = 20, + .iv = { 0xc0, 0x54, 0x3b, 0x59, 0xda, 0x48, 0xd9, 0x0b }, + .input = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }, + .ilen = 32, + .result = { 0x51, 0x04, 0xa1, 0x06, 0x16, 0x8a, 0x72, 0xd9, + 0x79, 0x0d, 0x41, 0xee, 0x8e, 0xda, 0xd3, 0x88, + 0xeb, 0x2e, 0x1e, 0xfc, 0x46, 0xda, 0x57, 0xc8, + 0xfc, 0xe6, 0x30, 0xdf, 0x91, 0x41, 0xbe, 0x28 }, + .rlen = 32, + }, { + .key = { 0x16, 0xaf, 0x5b, 0x14, 0x5f, 0xc9, 0xf5, 0x79, + 0xc1, 0x75, 0xf9, 0x3e, 0x3b, 0xfb, 0x0e, 0xed, + 0x86, 0x3d, 0x06, 0xcc, 0xfd, 0xb7, 0x85, 0x15, + 0x00, 0x00, 0x00, 0x48 }, + .klen = 28, + .iv = { 0x36, 0x73, 0x3c, 0x14, 0x7d, 0x6d, 0x93, 0xcb }, + .input = { "Single block msg" }, + .ilen = 16, + .result = { 0x4b, 0x55, 0x38, 0x4f, 0xe2, 0x59, 0xc9, 0xc8, + 0x4e, 0x79, 0x35, 0xa0, 0x03, 0xcb, 0xe9, 0x28 }, + .rlen = 16, + }, { + .key = { 0x7c, 0x5c, 0xb2, 0x40, 0x1b, 0x3d, 0xc3, 0x3c, + 0x19, 0xe7, 0x34, 0x08, 0x19, 0xe0, 0xf6, 0x9c, + 0x67, 0x8c, 0x3d, 0xb8, 0xe6, 0xf6, 0xa9, 0x1a, + 0x00, 0x96, 0xb0, 0x3b }, + .klen = 28, + .iv = { 0x02, 0x0c, 0x6e, 0xad, 0xc2, 0xcb, 0x50, 0x0d }, + .input = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }, + .ilen = 32, + .result = { 0x45, 0x32, 0x43, 0xfc, 0x60, 0x9b, 0x23, 0x32, + 0x7e, 0xdf, 0xaa, 0xfa, 0x71, 0x31, 0xcd, 0x9f, + 0x84, 0x90, 0x70, 0x1c, 0x5a, 0xd4, 0xa7, 0x9c, + 0xfc, 0x1f, 0xe0, 0xff, 0x42, 0xf4, 0xfb, 0x00 }, + .rlen = 32, + }, { + .key = { 0x77, 0x6b, 0xef, 0xf2, 0x85, 0x1d, 0xb0, 0x6f, + 0x4c, 0x8a, 0x05, 0x42, 0xc8, 0x69, 0x6f, 0x6c, + 0x6a, 0x81, 0xaf, 0x1e, 0xec, 0x96, 0xb4, 0xd3, + 0x7f, 0xc1, 0xd6, 0x89, 0xe6, 0xc1, 0xc1, 0x04, + 0x00, 0x00, 0x00, 0x60 }, + .klen = 36, + .iv = { 0xdb, 0x56, 0x72, 0xc9, 0x7a, 0xa8, 0xf0, 0xb2 }, + .input = { "Single block msg" }, + .ilen = 16, + .result = { 0x14, 0x5a, 0xd0, 0x1d, 0xbf, 0x82, 0x4e, 0xc7, + 0x56, 0x08, 0x63, 0xdc, 0x71, 0xe3, 0xe0, 0xc0 }, + .rlen = 16, + }, { + .key = { 0xf6, 0xd6, 0x6d, 0x6b, 0xd5, 0x2d, 0x59, 0xbb, + 0x07, 0x96, 0x36, 0x58, 0x79, 0xef, 0xf8, 0x86, + 0xc6, 0x6d, 0xd5, 0x1a, 0x5b, 0x6a, 0x99, 0x74, + 0x4b, 0x50, 0x59, 0x0c, 0x87, 0xa2, 0x38, 0x84, + 0x00, 0xfa, 0xac, 0x24 }, + .klen = 36, + .iv = { 0xc1, 0x58, 0x5e, 0xf1, 0x5a, 0x43, 0xd8, 0x75 }, + .input = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }, + .ilen = 32, + .result = { 0xf0, 0x5e, 0x23, 0x1b, 0x38, 0x94, 0x61, 0x2c, + 0x49, 0xee, 0x00, 0x0b, 0x80, 0x4e, 0xb2, 0xa9, + 0xb8, 0x30, 0x6b, 0x50, 0x8f, 0x83, 0x9d, 0x6a, + 0x55, 0x30, 0x83, 0x1d, 0x93, 0x44, 0xaf, 0x1c }, + .rlen = 32, + }, { + // generated using Crypto++ + .key = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x00, 0x00, 0x00, 0x00, + }, + .klen = 32 + 4, + .iv = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .input = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, + 0x00, 0x03, 0x06, 0x09, 0x0c, 0x0f, 0x12, 0x15, + 0x18, 0x1b, 0x1e, 0x21, 0x24, 0x27, 0x2a, 0x2d, + 0x30, 0x33, 0x36, 0x39, 0x3c, 0x3f, 0x42, 0x45, + 0x48, 0x4b, 0x4e, 0x51, 0x54, 0x57, 0x5a, 0x5d, + 0x60, 0x63, 0x66, 0x69, 0x6c, 0x6f, 0x72, 0x75, + 0x78, 0x7b, 0x7e, 0x81, 0x84, 0x87, 0x8a, 0x8d, + 0x90, 0x93, 0x96, 0x99, 0x9c, 0x9f, 0xa2, 0xa5, + 0xa8, 0xab, 0xae, 0xb1, 0xb4, 0xb7, 0xba, 0xbd, + 0xc0, 0xc3, 0xc6, 0xc9, 0xcc, 0xcf, 0xd2, 0xd5, + 0xd8, 0xdb, 0xde, 0xe1, 0xe4, 0xe7, 0xea, 0xed, + 0xf0, 0xf3, 0xf6, 0xf9, 0xfc, 0xff, 0x02, 0x05, + 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17, 0x1a, 0x1d, + 0x20, 0x23, 0x26, 0x29, 0x2c, 0x2f, 0x32, 0x35, + 0x38, 0x3b, 0x3e, 0x41, 0x44, 0x47, 0x4a, 0x4d, + 0x50, 0x53, 0x56, 0x59, 0x5c, 0x5f, 0x62, 0x65, + 0x68, 0x6b, 0x6e, 0x71, 0x74, 0x77, 0x7a, 0x7d, + 0x80, 0x83, 0x86, 0x89, 0x8c, 0x8f, 0x92, 0x95, + 0x98, 0x9b, 0x9e, 0xa1, 0xa4, 0xa7, 0xaa, 0xad, + 0xb0, 0xb3, 0xb6, 0xb9, 0xbc, 0xbf, 0xc2, 0xc5, + 0xc8, 0xcb, 0xce, 0xd1, 0xd4, 0xd7, 0xda, 0xdd, + 0xe0, 0xe3, 0xe6, 0xe9, 0xec, 0xef, 0xf2, 0xf5, + 0xf8, 0xfb, 0xfe, 0x01, 0x04, 0x07, 0x0a, 0x0d, + 0x10, 0x13, 0x16, 0x19, 0x1c, 0x1f, 0x22, 0x25, + 0x28, 0x2b, 0x2e, 0x31, 0x34, 0x37, 0x3a, 0x3d, + 0x40, 0x43, 0x46, 0x49, 0x4c, 0x4f, 0x52, 0x55, + 0x58, 0x5b, 0x5e, 0x61, 0x64, 0x67, 0x6a, 0x6d, + 0x70, 0x73, 0x76, 0x79, 0x7c, 0x7f, 0x82, 0x85, + 0x88, 0x8b, 0x8e, 0x91, 0x94, 0x97, 0x9a, 0x9d, + 0xa0, 0xa3, 0xa6, 0xa9, 0xac, 0xaf, 0xb2, 0xb5, + 0xb8, 0xbb, 0xbe, 0xc1, 0xc4, 0xc7, 0xca, 0xcd, + 0xd0, 0xd3, 0xd6, 0xd9, 0xdc, 0xdf, 0xe2, 0xe5, + 0xe8, 0xeb, 0xee, 0xf1, 0xf4, 0xf7, 0xfa, 0xfd, + 0x00, 0x05, 0x0a, 0x0f, 0x14, 0x19, 0x1e, 0x23, + 0x28, 0x2d, 0x32, 0x37, 0x3c, 0x41, 0x46, 0x4b, + 0x50, 0x55, 0x5a, 0x5f, 0x64, 0x69, 0x6e, 0x73, + 0x78, 0x7d, 0x82, 0x87, 0x8c, 0x91, 0x96, 0x9b, + 0xa0, 0xa5, 0xaa, 0xaf, 0xb4, 0xb9, 0xbe, 0xc3, + 0xc8, 0xcd, 0xd2, 0xd7, 0xdc, 0xe1, 0xe6, 0xeb, + 0xf0, 0xf5, 0xfa, 0xff, 0x04, 0x09, 0x0e, 0x13, + 0x18, 0x1d, 0x22, 0x27, 0x2c, 0x31, 0x36, 0x3b, + 0x40, 0x45, 0x4a, 0x4f, 0x54, 0x59, 0x5e, 0x63, + 0x68, 0x6d, 0x72, 0x77, 0x7c, 0x81, 0x86, 0x8b, + 0x90, 0x95, 0x9a, 0x9f, 0xa4, 0xa9, 0xae, 0xb3, + 0xb8, 0xbd, 0xc2, 0xc7, 0xcc, 0xd1, 0xd6, 0xdb, + 0xe0, 0xe5, 0xea, 0xef, 0xf4, 0xf9, 0xfe, 0x03, + 0x08, 0x0d, 0x12, 0x17, 0x1c, 0x21, 0x26, 0x2b, + 0x30, 0x35, 0x3a, 0x3f, 0x44, 0x49, 0x4e, 0x53, + 0x58, 0x5d, 0x62, 0x67, 0x6c, 0x71, 0x76, 0x7b, + 0x80, 0x85, 0x8a, 0x8f, 0x94, 0x99, 0x9e, 0xa3, + 0xa8, 0xad, 0xb2, 0xb7, 0xbc, 0xc1, 0xc6, 0xcb, + 0xd0, 0xd5, 0xda, 0xdf, 0xe4, 0xe9, 0xee, 0xf3, + 0xf8, 0xfd, 0x02, 0x07, 0x0c, 0x11, 0x16, 0x1b, + 0x20, 0x25, 0x2a, 0x2f, 0x34, 0x39, 0x3e, 0x43, + 0x48, 0x4d, 0x52, 0x57, 0x5c, 0x61, 0x66, 0x6b, + 0x70, 0x75, 0x7a, 0x7f, 0x84, 0x89, 0x8e, 0x93, + 0x98, 0x9d, 0xa2, 0xa7, 0xac, 0xb1, 0xb6, 0xbb, + 0xc0, 0xc5, 0xca, 0xcf, 0xd4, 0xd9, 0xde, 0xe3, + 0xe8, 0xed, 0xf2, 0xf7, 0xfc, 0x01, 0x06, 0x0b, + 0x10, 0x15, 0x1a, 0x1f, 0x24, 0x29, 0x2e, 0x33, + 0x38, 0x3d, 0x42, 0x47, 0x4c, 0x51, 0x56, 0x5b, + 0x60, 0x65, 0x6a, 0x6f, 0x74, 0x79, 0x7e, 0x83, + 0x88, 0x8d, 0x92, 0x97, 0x9c, 0xa1, 0xa6, 0xab, + 0xb0, 0xb5, 0xba, 0xbf, 0xc4, 0xc9, 0xce, 0xd3, + 0xd8, 0xdd, 0xe2, 0xe7, 0xec, 0xf1, 0xf6, 0xfb, + 0x00, 0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31, + 0x38, 0x3f, 0x46, 0x4d, 0x54, 0x5b, 0x62, 0x69, + 0x70, 0x77, 0x7e, 0x85, 0x8c, 0x93, 0x9a, 0xa1, + 0xa8, 0xaf, 0xb6, 0xbd, 0xc4, 0xcb, 0xd2, 0xd9, + 0xe0, 0xe7, 0xee, 0xf5, 0xfc, 0x03, 0x0a, 0x11, + 0x18, 0x1f, 0x26, 0x2d, 0x34, 0x3b, 0x42, 0x49, + 0x50, 0x57, 0x5e, 0x65, 0x6c, 0x73, 0x7a, 0x81, + 0x88, 0x8f, 0x96, 0x9d, 0xa4, 0xab, 0xb2, 0xb9, + 0xc0, 0xc7, 0xce, 0xd5, 0xdc, 0xe3, 0xea, 0xf1, + 0xf8, 0xff, 0x06, 0x0d, 0x14, 0x1b, 0x22, 0x29, + 0x30, 0x37, 0x3e, 0x45, 0x4c, 0x53, 0x5a, 0x61, + 0x68, 0x6f, 0x76, 0x7d, 0x84, 0x8b, 0x92, 0x99, + 0xa0, 0xa7, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd1, + 0xd8, 0xdf, 0xe6, 0xed, 0xf4, 0xfb, 0x02, 0x09, + 0x10, 0x17, 0x1e, 0x25, 0x2c, 0x33, 0x3a, 0x41, + 0x48, 0x4f, 0x56, 0x5d, 0x64, 0x6b, 0x72, 0x79, + 0x80, 0x87, 0x8e, 0x95, 0x9c, 0xa3, 0xaa, 0xb1, + 0xb8, 0xbf, 0xc6, 0xcd, 0xd4, 0xdb, 0xe2, 0xe9, + 0xf0, 0xf7, 0xfe, 0x05, 0x0c, 0x13, 0x1a, 0x21, + 0x28, 0x2f, 0x36, 0x3d, 0x44, 0x4b, 0x52, 0x59, + 0x60, 0x67, 0x6e, 0x75, 0x7c, 0x83, 0x8a, 0x91, + 0x98, 0x9f, 0xa6, 0xad, 0xb4, 0xbb, 0xc2, 0xc9, + 0xd0, 0xd7, 0xde, 0xe5, 0xec, 0xf3, 0xfa, 0x01, + 0x08, 0x0f, 0x16, 0x1d, 0x24, 0x2b, 0x32, 0x39, + 0x40, 0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, + 0x78, 0x7f, 0x86, 0x8d, 0x94, 0x9b, 0xa2, 0xa9, + 0xb0, 0xb7, 0xbe, 0xc5, 0xcc, 0xd3, 0xda, 0xe1, + 0xe8, 0xef, 0xf6, 0xfd, 0x04, 0x0b, 0x12, 0x19, + 0x20, 0x27, 0x2e, 0x35, 0x3c, 0x43, 0x4a, 0x51, + 0x58, 0x5f, 0x66, 0x6d, 0x74, 0x7b, 0x82, 0x89, + 0x90, 0x97, 0x9e, 0xa5, 0xac, 0xb3, 0xba, 0xc1, + 0xc8, 0xcf, 0xd6, 0xdd, 0xe4, 0xeb, 0xf2, 0xf9, + 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, + 0x48, 0x51, 0x5a, 0x63, 0x6c, 0x75, 0x7e, 0x87, + 0x90, 0x99, 0xa2, 0xab, 0xb4, 0xbd, 0xc6, 0xcf, + 0xd8, 0xe1, 0xea, 0xf3, 0xfc, 0x05, 0x0e, 0x17, + 0x20, 0x29, 0x32, 0x3b, 0x44, 0x4d, 0x56, 0x5f, + 0x68, 0x71, 0x7a, 0x83, 0x8c, 0x95, 0x9e, 0xa7, + 0xb0, 0xb9, 0xc2, 0xcb, 0xd4, 0xdd, 0xe6, 0xef, + 0xf8, 0x01, 0x0a, 0x13, 0x1c, 0x25, 0x2e, 0x37, + 0x40, 0x49, 0x52, 0x5b, 0x64, 0x6d, 0x76, 0x7f, + 0x88, 0x91, 0x9a, 0xa3, 0xac, 0xb5, 0xbe, 0xc7, + 0xd0, 0xd9, 0xe2, 0xeb, 0xf4, 0xfd, 0x06, 0x0f, + 0x18, 0x21, 0x2a, 0x33, 0x3c, 0x45, 0x4e, 0x57, + 0x60, 0x69, 0x72, 0x7b, 0x84, 0x8d, 0x96, 0x9f, + 0xa8, 0xb1, 0xba, 0xc3, 0xcc, 0xd5, 0xde, 0xe7, + 0xf0, 0xf9, 0x02, 0x0b, 0x14, 0x1d, 0x26, 0x2f, + 0x38, 0x41, 0x4a, 0x53, 0x5c, 0x65, 0x6e, 0x77, + 0x80, 0x89, 0x92, 0x9b, 0xa4, 0xad, 0xb6, 0xbf, + 0xc8, 0xd1, 0xda, 0xe3, 0xec, 0xf5, 0xfe, 0x07, + 0x10, 0x19, 0x22, 0x2b, 0x34, 0x3d, 0x46, 0x4f, + 0x58, 0x61, 0x6a, 0x73, 0x7c, 0x85, 0x8e, 0x97, + 0xa0, 0xa9, 0xb2, 0xbb, 0xc4, 0xcd, 0xd6, 0xdf, + 0xe8, 0xf1, 0xfa, 0x03, 0x0c, 0x15, 0x1e, 0x27, + 0x30, 0x39, 0x42, 0x4b, 0x54, 0x5d, 0x66, 0x6f, + 0x78, 0x81, 0x8a, 0x93, 0x9c, 0xa5, 0xae, 0xb7, + 0xc0, 0xc9, 0xd2, 0xdb, 0xe4, 0xed, 0xf6, 0xff, + 0x08, 0x11, 0x1a, 0x23, 0x2c, 0x35, 0x3e, 0x47, + 0x50, 0x59, 0x62, 0x6b, 0x74, 0x7d, 0x86, 0x8f, + 0x98, 0xa1, 0xaa, 0xb3, 0xbc, 0xc5, 0xce, 0xd7, + 0xe0, 0xe9, 0xf2, 0xfb, 0x04, 0x0d, 0x16, 0x1f, + 0x28, 0x31, 0x3a, 0x43, 0x4c, 0x55, 0x5e, 0x67, + 0x70, 0x79, 0x82, 0x8b, 0x94, 0x9d, 0xa6, 0xaf, + 0xb8, 0xc1, 0xca, 0xd3, 0xdc, 0xe5, 0xee, 0xf7, + 0x00, 0x0b, 0x16, 0x21, 0x2c, 0x37, 0x42, 0x4d, + 0x58, 0x63, 0x6e, 0x79, 0x84, 0x8f, 0x9a, 0xa5, + 0xb0, 0xbb, 0xc6, 0xd1, 0xdc, 0xe7, 0xf2, 0xfd, + 0x08, 0x13, 0x1e, 0x29, 0x34, 0x3f, 0x4a, 0x55, + 0x60, 0x6b, 0x76, 0x81, 0x8c, 0x97, 0xa2, 0xad, + 0xb8, 0xc3, 0xce, 0xd9, 0xe4, 0xef, 0xfa, 0x05, + 0x10, 0x1b, 0x26, 0x31, 0x3c, 0x47, 0x52, 0x5d, + 0x68, 0x73, 0x7e, 0x89, 0x94, 0x9f, 0xaa, 0xb5, + 0xc0, 0xcb, 0xd6, 0xe1, 0xec, 0xf7, 0x02, 0x0d, + 0x18, 0x23, 0x2e, 0x39, 0x44, 0x4f, 0x5a, 0x65, + 0x70, 0x7b, 0x86, 0x91, 0x9c, 0xa7, 0xb2, 0xbd, + 0xc8, 0xd3, 0xde, 0xe9, 0xf4, 0xff, 0x0a, 0x15, + 0x20, 0x2b, 0x36, 0x41, 0x4c, 0x57, 0x62, 0x6d, + 0x78, 0x83, 0x8e, 0x99, 0xa4, 0xaf, 0xba, 0xc5, + 0xd0, 0xdb, 0xe6, 0xf1, 0xfc, 0x07, 0x12, 0x1d, + 0x28, 0x33, 0x3e, 0x49, 0x54, 0x5f, 0x6a, 0x75, + 0x80, 0x8b, 0x96, 0xa1, 0xac, 0xb7, 0xc2, 0xcd, + 0xd8, 0xe3, 0xee, 0xf9, 0x04, 0x0f, 0x1a, 0x25, + 0x30, 0x3b, 0x46, 0x51, 0x5c, 0x67, 0x72, 0x7d, + 0x88, 0x93, 0x9e, 0xa9, 0xb4, 0xbf, 0xca, 0xd5, + 0xe0, 0xeb, 0xf6, 0x01, 0x0c, 0x17, 0x22, 0x2d, + 0x38, 0x43, 0x4e, 0x59, 0x64, 0x6f, 0x7a, 0x85, + 0x90, 0x9b, 0xa6, 0xb1, 0xbc, 0xc7, 0xd2, 0xdd, + 0xe8, 0xf3, 0xfe, 0x09, 0x14, 0x1f, 0x2a, 0x35, + 0x40, 0x4b, 0x56, 0x61, 0x6c, 0x77, 0x82, 0x8d, + 0x98, 0xa3, 0xae, 0xb9, 0xc4, 0xcf, 0xda, 0xe5, + 0xf0, 0xfb, 0x06, 0x11, 0x1c, 0x27, 0x32, 0x3d, + 0x48, 0x53, 0x5e, 0x69, 0x74, 0x7f, 0x8a, 0x95, + 0xa0, 0xab, 0xb6, 0xc1, 0xcc, 0xd7, 0xe2, 0xed, + 0xf8, 0x03, 0x0e, 0x19, 0x24, 0x2f, 0x3a, 0x45, + 0x50, 0x5b, 0x66, 0x71, 0x7c, 0x87, 0x92, 0x9d, + 0xa8, 0xb3, 0xbe, 0xc9, 0xd4, 0xdf, 0xea, 0xf5, + 0x00, 0x0d, 0x1a, 0x27, 0x34, 0x41, 0x4e, 0x5b, + 0x68, 0x75, 0x82, 0x8f, 0x9c, 0xa9, 0xb6, 0xc3, + 0xd0, 0xdd, 0xea, 0xf7, 0x04, 0x11, 0x1e, 0x2b, + 0x38, 0x45, 0x52, 0x5f, 0x6c, 0x79, 0x86, 0x93, + 0xa0, 0xad, 0xba, 0xc7, 0xd4, 0xe1, 0xee, 0xfb, + 0x08, 0x15, 0x22, 0x2f, 0x3c, 0x49, 0x56, 0x63, + 0x70, 0x7d, 0x8a, 0x97, 0xa4, 0xb1, 0xbe, 0xcb, + 0xd8, 0xe5, 0xf2, 0xff, 0x0c, 0x19, 0x26, 0x33, + 0x40, 0x4d, 0x5a, 0x67, 0x74, 0x81, 0x8e, 0x9b, + 0xa8, 0xb5, 0xc2, 0xcf, 0xdc, 0xe9, 0xf6, 0x03, + 0x10, 0x1d, 0x2a, 0x37, 0x44, 0x51, 0x5e, 0x6b, + 0x78, 0x85, 0x92, 0x9f, 0xac, 0xb9, 0xc6, 0xd3, + 0xe0, 0xed, 0xfa, 0x07, 0x14, 0x21, 0x2e, 0x3b, + 0x48, 0x55, 0x62, 0x6f, 0x7c, 0x89, 0x96, 0xa3, + 0xb0, 0xbd, 0xca, 0xd7, 0xe4, 0xf1, 0xfe, 0x0b, + 0x18, 0x25, 0x32, 0x3f, 0x4c, 0x59, 0x66, 0x73, + 0x80, 0x8d, 0x9a, 0xa7, 0xb4, 0xc1, 0xce, 0xdb, + 0xe8, 0xf5, 0x02, 0x0f, 0x1c, 0x29, 0x36, 0x43, + 0x50, 0x5d, 0x6a, 0x77, 0x84, 0x91, 0x9e, 0xab, + 0xb8, 0xc5, 0xd2, 0xdf, 0xec, 0xf9, 0x06, 0x13, + 0x20, 0x2d, 0x3a, 0x47, 0x54, 0x61, 0x6e, 0x7b, + 0x88, 0x95, 0xa2, 0xaf, 0xbc, 0xc9, 0xd6, 0xe3, + 0xf0, 0xfd, 0x0a, 0x17, 0x24, 0x31, 0x3e, 0x4b, + 0x58, 0x65, 0x72, 0x7f, 0x8c, 0x99, 0xa6, 0xb3, + 0xc0, 0xcd, 0xda, 0xe7, 0xf4, 0x01, 0x0e, 0x1b, + 0x28, 0x35, 0x42, 0x4f, 0x5c, 0x69, 0x76, 0x83, + 0x90, 0x9d, 0xaa, 0xb7, 0xc4, 0xd1, 0xde, 0xeb, + 0xf8, 0x05, 0x12, 0x1f, 0x2c, 0x39, 0x46, 0x53, + 0x60, 0x6d, 0x7a, 0x87, 0x94, 0xa1, 0xae, 0xbb, + 0xc8, 0xd5, 0xe2, 0xef, 0xfc, 0x09, 0x16, 0x23, + 0x30, 0x3d, 0x4a, 0x57, 0x64, 0x71, 0x7e, 0x8b, + 0x98, 0xa5, 0xb2, 0xbf, 0xcc, 0xd9, 0xe6, 0xf3, + 0x00, 0x0f, 0x1e, 0x2d, 0x3c, 0x4b, 0x5a, 0x69, + 0x78, 0x87, 0x96, 0xa5, 0xb4, 0xc3, 0xd2, 0xe1, + 0xf0, 0xff, 0x0e, 0x1d, 0x2c, 0x3b, 0x4a, 0x59, + 0x68, 0x77, 0x86, 0x95, 0xa4, 0xb3, 0xc2, 0xd1, + 0xe0, 0xef, 0xfe, 0x0d, 0x1c, 0x2b, 0x3a, 0x49, + 0x58, 0x67, 0x76, 0x85, 0x94, 0xa3, 0xb2, 0xc1, + 0xd0, 0xdf, 0xee, 0xfd, 0x0c, 0x1b, 0x2a, 0x39, + 0x48, 0x57, 0x66, 0x75, 0x84, 0x93, 0xa2, 0xb1, + 0xc0, 0xcf, 0xde, 0xed, 0xfc, 0x0b, 0x1a, 0x29, + 0x38, 0x47, 0x56, 0x65, 0x74, 0x83, 0x92, 0xa1, + 0xb0, 0xbf, 0xce, 0xdd, 0xec, 0xfb, 0x0a, 0x19, + 0x28, 0x37, 0x46, 0x55, 0x64, 0x73, 0x82, 0x91, + 0xa0, 0xaf, 0xbe, 0xcd, 0xdc, 0xeb, 0xfa, 0x09, + 0x18, 0x27, 0x36, 0x45, 0x54, 0x63, 0x72, 0x81, + 0x90, 0x9f, 0xae, 0xbd, 0xcc, 0xdb, 0xea, 0xf9, + 0x08, 0x17, 0x26, 0x35, 0x44, 0x53, 0x62, 0x71, + 0x80, 0x8f, 0x9e, 0xad, 0xbc, 0xcb, 0xda, 0xe9, + 0xf8, 0x07, 0x16, 0x25, 0x34, 0x43, 0x52, 0x61, + 0x70, 0x7f, 0x8e, 0x9d, 0xac, 0xbb, 0xca, 0xd9, + 0xe8, 0xf7, 0x06, 0x15, 0x24, 0x33, 0x42, 0x51, + 0x60, 0x6f, 0x7e, 0x8d, 0x9c, 0xab, 0xba, 0xc9, + 0xd8, 0xe7, 0xf6, 0x05, 0x14, 0x23, 0x32, 0x41, + 0x50, 0x5f, 0x6e, 0x7d, 0x8c, 0x9b, 0xaa, 0xb9, + 0xc8, 0xd7, 0xe6, 0xf5, 0x04, 0x13, 0x22, 0x31, + 0x40, 0x4f, 0x5e, 0x6d, 0x7c, 0x8b, 0x9a, 0xa9, + 0xb8, 0xc7, 0xd6, 0xe5, 0xf4, 0x03, 0x12, 0x21, + 0x30, 0x3f, 0x4e, 0x5d, 0x6c, 0x7b, 0x8a, 0x99, + 0xa8, 0xb7, 0xc6, 0xd5, 0xe4, 0xf3, 0x02, 0x11, + 0x20, 0x2f, 0x3e, 0x4d, 0x5c, 0x6b, 0x7a, 0x89, + 0x98, 0xa7, 0xb6, 0xc5, 0xd4, 0xe3, 0xf2, 0x01, + 0x10, 0x1f, 0x2e, 0x3d, 0x4c, 0x5b, 0x6a, 0x79, + 0x88, 0x97, 0xa6, 0xb5, 0xc4, 0xd3, 0xe2, 0xf1, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, + 0x10, 0x21, 0x32, 0x43, 0x54, 0x65, 0x76, 0x87, + 0x98, 0xa9, 0xba, 0xcb, 0xdc, 0xed, 0xfe, 0x0f, + 0x20, 0x31, 0x42, 0x53, 0x64, 0x75, 0x86, 0x97, + 0xa8, 0xb9, 0xca, 0xdb, 0xec, 0xfd, 0x0e, 0x1f, + 0x30, 0x41, 0x52, 0x63, 0x74, 0x85, 0x96, 0xa7, + 0xb8, 0xc9, 0xda, 0xeb, 0xfc, 0x0d, 0x1e, 0x2f, + 0x40, 0x51, 0x62, 0x73, 0x84, 0x95, 0xa6, 0xb7, + 0xc8, 0xd9, 0xea, 0xfb, 0x0c, 0x1d, 0x2e, 0x3f, + 0x50, 0x61, 0x72, 0x83, 0x94, 0xa5, 0xb6, 0xc7, + 0xd8, 0xe9, 0xfa, 0x0b, 0x1c, 0x2d, 0x3e, 0x4f, + 0x60, 0x71, 0x82, 0x93, 0xa4, 0xb5, 0xc6, 0xd7, + 0xe8, 0xf9, 0x0a, 0x1b, 0x2c, 0x3d, 0x4e, 0x5f, + 0x70, 0x81, 0x92, 0xa3, 0xb4, 0xc5, 0xd6, 0xe7, + 0xf8, 0x09, 0x1a, 0x2b, 0x3c, 0x4d, 0x5e, 0x6f, + 0x80, 0x91, 0xa2, 0xb3, 0xc4, 0xd5, 0xe6, 0xf7, + 0x08, 0x19, 0x2a, 0x3b, 0x4c, 0x5d, 0x6e, 0x7f, + 0x90, 0xa1, 0xb2, 0xc3, 0xd4, 0xe5, 0xf6, 0x07, + 0x18, 0x29, 0x3a, 0x4b, 0x5c, 0x6d, 0x7e, 0x8f, + 0xa0, 0xb1, 0xc2, 0xd3, 0xe4, 0xf5, 0x06, 0x17, + 0x28, 0x39, 0x4a, 0x5b, 0x6c, 0x7d, 0x8e, 0x9f, + 0xb0, 0xc1, 0xd2, 0xe3, 0xf4, 0x05, 0x16, 0x27, + 0x38, 0x49, 0x5a, 0x6b, 0x7c, 0x8d, 0x9e, 0xaf, + 0xc0, 0xd1, 0xe2, 0xf3, 0x04, 0x15, 0x26, 0x37, + 0x48, 0x59, 0x6a, 0x7b, 0x8c, 0x9d, 0xae, 0xbf, + 0xd0, 0xe1, 0xf2, 0x03, 0x14, 0x25, 0x36, 0x47, + 0x58, 0x69, 0x7a, 0x8b, 0x9c, 0xad, 0xbe, 0xcf, + 0xe0, 0xf1, 0x02, 0x13, 0x24, 0x35, 0x46, 0x57, + 0x68, 0x79, 0x8a, 0x9b, 0xac, 0xbd, 0xce, 0xdf, + 0xf0, 0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, + 0x78, 0x89, 0x9a, 0xab, 0xbc, 0xcd, 0xde, 0xef, + 0x00, 0x13, 0x26, 0x39, 0x4c, 0x5f, 0x72, 0x85, + 0x98, 0xab, 0xbe, 0xd1, 0xe4, 0xf7, 0x0a, 0x1d, + 0x30, 0x43, 0x56, 0x69, 0x7c, 0x8f, 0xa2, 0xb5, + 0xc8, 0xdb, 0xee, 0x01, 0x14, 0x27, 0x3a, 0x4d, + 0x60, 0x73, 0x86, 0x99, 0xac, 0xbf, 0xd2, 0xe5, + 0xf8, 0x0b, 0x1e, 0x31, 0x44, 0x57, 0x6a, 0x7d, + 0x90, 0xa3, 0xb6, 0xc9, 0xdc, 0xef, 0x02, 0x15, + 0x28, 0x3b, 0x4e, 0x61, 0x74, 0x87, 0x9a, 0xad, + 0xc0, 0xd3, 0xe6, 0xf9, 0x0c, 0x1f, 0x32, 0x45, + 0x58, 0x6b, 0x7e, 0x91, 0xa4, 0xb7, 0xca, 0xdd, + 0xf0, 0x03, 0x16, 0x29, 0x3c, 0x4f, 0x62, 0x75, + 0x88, 0x9b, 0xae, 0xc1, 0xd4, 0xe7, 0xfa, 0x0d, + 0x20, 0x33, 0x46, 0x59, 0x6c, 0x7f, 0x92, 0xa5, + 0xb8, 0xcb, 0xde, 0xf1, 0x04, 0x17, 0x2a, 0x3d, + 0x50, 0x63, 0x76, 0x89, 0x9c, 0xaf, 0xc2, 0xd5, + 0xe8, 0xfb, 0x0e, 0x21, 0x34, 0x47, 0x5a, 0x6d, + 0x80, 0x93, 0xa6, 0xb9, 0xcc, 0xdf, 0xf2, 0x05, + 0x18, 0x2b, 0x3e, 0x51, 0x64, 0x77, 0x8a, 0x9d, + 0xb0, 0xc3, 0xd6, 0xe9, 0xfc, 0x0f, 0x22, 0x35, + 0x48, 0x5b, 0x6e, 0x81, 0x94, 0xa7, 0xba, 0xcd, + 0xe0, 0xf3, 0x06, 0x19, 0x2c, 0x3f, 0x52, 0x65, + 0x78, 0x8b, 0x9e, 0xb1, 0xc4, 0xd7, 0xea, 0xfd, + 0x10, 0x23, 0x36, 0x49, 0x5c, 0x6f, 0x82, 0x95, + 0xa8, 0xbb, 0xce, 0xe1, 0xf4, 0x07, 0x1a, 0x2d, + 0x40, 0x53, 0x66, 0x79, 0x8c, 0x9f, 0xb2, 0xc5, + 0xd8, 0xeb, 0xfe, 0x11, 0x24, 0x37, 0x4a, 0x5d, + 0x70, 0x83, 0x96, 0xa9, 0xbc, 0xcf, 0xe2, 0xf5, + 0x08, 0x1b, 0x2e, 0x41, 0x54, 0x67, 0x7a, 0x8d, + 0xa0, 0xb3, 0xc6, 0xd9, 0xec, 0xff, 0x12, 0x25, + 0x38, 0x4b, 0x5e, 0x71, 0x84, 0x97, 0xaa, 0xbd, + 0xd0, 0xe3, 0xf6, 0x09, 0x1c, 0x2f, 0x42, 0x55, + 0x68, 0x7b, 0x8e, 0xa1, 0xb4, 0xc7, 0xda, 0xed, + 0x00, 0x15, 0x2a, 0x3f, 0x54, 0x69, 0x7e, 0x93, + 0xa8, 0xbd, 0xd2, 0xe7, 0xfc, 0x11, 0x26, 0x3b, + 0x50, 0x65, 0x7a, 0x8f, 0xa4, 0xb9, 0xce, 0xe3, + 0xf8, 0x0d, 0x22, 0x37, 0x4c, 0x61, 0x76, 0x8b, + 0xa0, 0xb5, 0xca, 0xdf, 0xf4, 0x09, 0x1e, 0x33, + 0x48, 0x5d, 0x72, 0x87, 0x9c, 0xb1, 0xc6, 0xdb, + 0xf0, 0x05, 0x1a, 0x2f, 0x44, 0x59, 0x6e, 0x83, + 0x98, 0xad, 0xc2, 0xd7, 0xec, 0x01, 0x16, 0x2b, + 0x40, 0x55, 0x6a, 0x7f, 0x94, 0xa9, 0xbe, 0xd3, + 0xe8, 0xfd, 0x12, 0x27, 0x3c, 0x51, 0x66, 0x7b, + 0x90, 0xa5, 0xba, 0xcf, 0xe4, 0xf9, 0x0e, 0x23, + 0x38, 0x4d, 0x62, 0x77, 0x8c, 0xa1, 0xb6, 0xcb, + 0xe0, 0xf5, 0x0a, 0x1f, 0x34, 0x49, 0x5e, 0x73, + 0x88, 0x9d, 0xb2, 0xc7, 0xdc, 0xf1, 0x06, 0x1b, + 0x30, 0x45, 0x5a, 0x6f, 0x84, 0x99, 0xae, 0xc3, + 0xd8, 0xed, 0x02, 0x17, 0x2c, 0x41, 0x56, 0x6b, + 0x80, 0x95, 0xaa, 0xbf, 0xd4, 0xe9, 0xfe, 0x13, + 0x28, 0x3d, 0x52, 0x67, 0x7c, 0x91, 0xa6, 0xbb, + 0xd0, 0xe5, 0xfa, 0x0f, 0x24, 0x39, 0x4e, 0x63, + 0x78, 0x8d, 0xa2, 0xb7, 0xcc, 0xe1, 0xf6, 0x0b, + 0x20, 0x35, 0x4a, 0x5f, 0x74, 0x89, 0x9e, 0xb3, + 0xc8, 0xdd, 0xf2, 0x07, 0x1c, 0x31, 0x46, 0x5b, + 0x70, 0x85, 0x9a, 0xaf, 0xc4, 0xd9, 0xee, 0x03, + 0x18, 0x2d, 0x42, 0x57, 0x6c, 0x81, 0x96, 0xab, + 0xc0, 0xd5, 0xea, 0xff, 0x14, 0x29, 0x3e, 0x53, + 0x68, 0x7d, 0x92, 0xa7, 0xbc, 0xd1, 0xe6, 0xfb, + 0x10, 0x25, 0x3a, 0x4f, 0x64, 0x79, 0x8e, 0xa3, + 0xb8, 0xcd, 0xe2, 0xf7, 0x0c, 0x21, 0x36, 0x4b, + 0x60, 0x75, 0x8a, 0x9f, 0xb4, 0xc9, 0xde, 0xf3, + 0x08, 0x1d, 0x32, 0x47, 0x5c, 0x71, 0x86, 0x9b, + 0xb0, 0xc5, 0xda, 0xef, 0x04, 0x19, 0x2e, 0x43, + 0x58, 0x6d, 0x82, 0x97, 0xac, 0xc1, 0xd6, 0xeb, + 0x00, 0x17, 0x2e, 0x45, 0x5c, 0x73, 0x8a, 0xa1, + 0xb8, 0xcf, 0xe6, 0xfd, 0x14, 0x2b, 0x42, 0x59, + 0x70, 0x87, 0x9e, 0xb5, 0xcc, 0xe3, 0xfa, 0x11, + 0x28, 0x3f, 0x56, 0x6d, 0x84, 0x9b, 0xb2, 0xc9, + 0xe0, 0xf7, 0x0e, 0x25, 0x3c, 0x53, 0x6a, 0x81, + 0x98, 0xaf, 0xc6, 0xdd, 0xf4, 0x0b, 0x22, 0x39, + 0x50, 0x67, 0x7e, 0x95, 0xac, 0xc3, 0xda, 0xf1, + 0x08, 0x1f, 0x36, 0x4d, 0x64, 0x7b, 0x92, 0xa9, + 0xc0, 0xd7, 0xee, 0x05, 0x1c, 0x33, 0x4a, 0x61, + 0x78, 0x8f, 0xa6, 0xbd, 0xd4, 0xeb, 0x02, 0x19, + 0x30, 0x47, 0x5e, 0x75, 0x8c, 0xa3, 0xba, 0xd1, + 0xe8, 0xff, 0x16, 0x2d, 0x44, 0x5b, 0x72, 0x89, + 0xa0, 0xb7, 0xce, 0xe5, 0xfc, 0x13, 0x2a, 0x41, + 0x58, 0x6f, 0x86, 0x9d, 0xb4, 0xcb, 0xe2, 0xf9, + 0x10, 0x27, 0x3e, 0x55, 0x6c, 0x83, 0x9a, 0xb1, + 0xc8, 0xdf, 0xf6, 0x0d, 0x24, 0x3b, 0x52, 0x69, + 0x80, 0x97, 0xae, 0xc5, 0xdc, 0xf3, 0x0a, 0x21, + 0x38, 0x4f, 0x66, 0x7d, 0x94, 0xab, 0xc2, 0xd9, + 0xf0, 0x07, 0x1e, 0x35, 0x4c, 0x63, 0x7a, 0x91, + 0xa8, 0xbf, 0xd6, 0xed, 0x04, 0x1b, 0x32, 0x49, + 0x60, 0x77, 0x8e, 0xa5, 0xbc, 0xd3, 0xea, 0x01, + 0x18, 0x2f, 0x46, 0x5d, 0x74, 0x8b, 0xa2, 0xb9, + 0xd0, 0xe7, 0xfe, 0x15, 0x2c, 0x43, 0x5a, 0x71, + 0x88, 0x9f, 0xb6, 0xcd, 0xe4, 0xfb, 0x12, 0x29, + 0x40, 0x57, 0x6e, 0x85, 0x9c, 0xb3, 0xca, 0xe1, + 0xf8, 0x0f, 0x26, 0x3d, 0x54, 0x6b, 0x82, 0x99, + 0xb0, 0xc7, 0xde, 0xf5, 0x0c, 0x23, 0x3a, 0x51, + 0x68, 0x7f, 0x96, 0xad, 0xc4, 0xdb, 0xf2, 0x09, + 0x20, 0x37, 0x4e, 0x65, 0x7c, 0x93, 0xaa, 0xc1, + 0xd8, 0xef, 0x06, 0x1d, 0x34, 0x4b, 0x62, 0x79, + 0x90, 0xa7, 0xbe, 0xd5, 0xec, 0x03, 0x1a, 0x31, + 0x48, 0x5f, 0x76, 0x8d, 0xa4, 0xbb, 0xd2, 0xe9, + 0x00, 0x19, 0x32, 0x4b, 0x64, 0x7d, 0x96, 0xaf, + 0xc8, 0xe1, 0xfa, 0x13, 0x2c, 0x45, 0x5e, 0x77, + 0x90, 0xa9, 0xc2, 0xdb, 0xf4, 0x0d, 0x26, 0x3f, + 0x58, 0x71, 0x8a, 0xa3, 0xbc, 0xd5, 0xee, 0x07, + 0x20, 0x39, 0x52, 0x6b, 0x84, 0x9d, 0xb6, 0xcf, + 0xe8, 0x01, 0x1a, 0x33, 0x4c, 0x65, 0x7e, 0x97, + 0xb0, 0xc9, 0xe2, 0xfb, 0x14, 0x2d, 0x46, 0x5f, + 0x78, 0x91, 0xaa, 0xc3, 0xdc, 0xf5, 0x0e, 0x27, + 0x40, 0x59, 0x72, 0x8b, 0xa4, 0xbd, 0xd6, 0xef, + 0x08, 0x21, 0x3a, 0x53, 0x6c, 0x85, 0x9e, 0xb7, + 0xd0, 0xe9, 0x02, 0x1b, 0x34, 0x4d, 0x66, 0x7f, + 0x98, 0xb1, 0xca, 0xe3, 0xfc, 0x15, 0x2e, 0x47, + 0x60, 0x79, 0x92, 0xab, 0xc4, 0xdd, 0xf6, 0x0f, + 0x28, 0x41, 0x5a, 0x73, 0x8c, 0xa5, 0xbe, 0xd7, + 0xf0, 0x09, 0x22, 0x3b, 0x54, 0x6d, 0x86, 0x9f, + 0xb8, 0xd1, 0xea, 0x03, 0x1c, 0x35, 0x4e, 0x67, + 0x80, 0x99, 0xb2, 0xcb, 0xe4, 0xfd, 0x16, 0x2f, + 0x48, 0x61, 0x7a, 0x93, 0xac, 0xc5, 0xde, 0xf7, + 0x10, 0x29, 0x42, 0x5b, 0x74, 0x8d, 0xa6, 0xbf, + 0xd8, 0xf1, 0x0a, 0x23, 0x3c, 0x55, 0x6e, 0x87, + 0xa0, 0xb9, 0xd2, 0xeb, 0x04, 0x1d, 0x36, 0x4f, + 0x68, 0x81, 0x9a, 0xb3, 0xcc, 0xe5, 0xfe, 0x17, + 0x30, 0x49, 0x62, 0x7b, 0x94, 0xad, 0xc6, 0xdf, + 0xf8, 0x11, 0x2a, 0x43, 0x5c, 0x75, 0x8e, 0xa7, + 0xc0, 0xd9, 0xf2, 0x0b, 0x24, 0x3d, 0x56, 0x6f, + 0x88, 0xa1, 0xba, 0xd3, 0xec, 0x05, 0x1e, 0x37, + 0x50, 0x69, 0x82, 0x9b, 0xb4, 0xcd, 0xe6, 0xff, + 0x18, 0x31, 0x4a, 0x63, 0x7c, 0x95, 0xae, 0xc7, + 0xe0, 0xf9, 0x12, 0x2b, 0x44, 0x5d, 0x76, 0x8f, + 0xa8, 0xc1, 0xda, 0xf3, 0x0c, 0x25, 0x3e, 0x57, + 0x70, 0x89, 0xa2, 0xbb, 0xd4, 0xed, 0x06, 0x1f, + 0x38, 0x51, 0x6a, 0x83, 0x9c, 0xb5, 0xce, 0xe7, + 0x00, 0x1b, 0x36, 0x51, 0x6c, 0x87, 0xa2, 0xbd, + 0xd8, 0xf3, 0x0e, 0x29, 0x44, 0x5f, 0x7a, 0x95, + 0xb0, 0xcb, 0xe6, 0x01, 0x1c, 0x37, 0x52, 0x6d, + 0x88, 0xa3, 0xbe, 0xd9, 0xf4, 0x0f, 0x2a, 0x45, + 0x60, 0x7b, 0x96, 0xb1, 0xcc, 0xe7, 0x02, 0x1d, + 0x38, 0x53, 0x6e, 0x89, 0xa4, 0xbf, 0xda, 0xf5, + 0x10, 0x2b, 0x46, 0x61, 0x7c, 0x97, 0xb2, 0xcd, + 0xe8, 0x03, 0x1e, 0x39, 0x54, 0x6f, 0x8a, 0xa5, + 0xc0, 0xdb, 0xf6, 0x11, 0x2c, 0x47, 0x62, 0x7d, + 0x98, 0xb3, 0xce, 0xe9, 0x04, 0x1f, 0x3a, 0x55, + 0x70, 0x8b, 0xa6, 0xc1, 0xdc, 0xf7, 0x12, 0x2d, + 0x48, 0x63, 0x7e, 0x99, 0xb4, 0xcf, 0xea, 0x05, + 0x20, 0x3b, 0x56, 0x71, 0x8c, 0xa7, 0xc2, 0xdd, + 0xf8, 0x13, 0x2e, 0x49, 0x64, 0x7f, 0x9a, 0xb5, + 0xd0, 0xeb, 0x06, 0x21, 0x3c, 0x57, 0x72, 0x8d, + 0xa8, 0xc3, 0xde, 0xf9, 0x14, 0x2f, 0x4a, 0x65, + 0x80, 0x9b, 0xb6, 0xd1, 0xec, 0x07, 0x22, 0x3d, + 0x58, 0x73, 0x8e, 0xa9, 0xc4, 0xdf, 0xfa, 0x15, + 0x30, 0x4b, 0x66, 0x81, 0x9c, 0xb7, 0xd2, 0xed, + 0x08, 0x23, 0x3e, 0x59, 0x74, 0x8f, 0xaa, 0xc5, + 0xe0, 0xfb, 0x16, 0x31, 0x4c, 0x67, 0x82, 0x9d, + 0xb8, 0xd3, 0xee, 0x09, 0x24, 0x3f, 0x5a, 0x75, + 0x90, 0xab, 0xc6, 0xe1, 0xfc, 0x17, 0x32, 0x4d, + 0x68, 0x83, 0x9e, 0xb9, 0xd4, 0xef, 0x0a, 0x25, + 0x40, 0x5b, 0x76, 0x91, 0xac, 0xc7, 0xe2, 0xfd, + 0x18, 0x33, 0x4e, 0x69, 0x84, 0x9f, 0xba, 0xd5, + 0xf0, 0x0b, 0x26, 0x41, 0x5c, 0x77, 0x92, 0xad, + 0xc8, 0xe3, 0xfe, 0x19, 0x34, 0x4f, 0x6a, 0x85, + 0xa0, 0xbb, 0xd6, 0xf1, 0x0c, 0x27, 0x42, 0x5d, + 0x78, 0x93, 0xae, 0xc9, 0xe4, 0xff, 0x1a, 0x35, + 0x50, 0x6b, 0x86, 0xa1, 0xbc, 0xd7, 0xf2, 0x0d, + 0x28, 0x43, 0x5e, 0x79, 0x94, 0xaf, 0xca, 0xe5, + 0x00, 0x1d, 0x3a, 0x57, 0x74, 0x91, 0xae, 0xcb, + 0xe8, 0x05, 0x22, 0x3f, 0x5c, 0x79, 0x96, 0xb3, + 0xd0, 0xed, 0x0a, 0x27, 0x44, 0x61, 0x7e, 0x9b, + 0xb8, 0xd5, 0xf2, 0x0f, 0x2c, 0x49, 0x66, 0x83, + 0xa0, 0xbd, 0xda, 0xf7, 0x14, 0x31, 0x4e, 0x6b, + 0x88, 0xa5, 0xc2, 0xdf, 0xfc, 0x19, 0x36, 0x53, + 0x70, 0x8d, 0xaa, 0xc7, 0xe4, 0x01, 0x1e, 0x3b, + 0x58, 0x75, 0x92, 0xaf, 0xcc, 0xe9, 0x06, 0x23, + 0x40, 0x5d, 0x7a, 0x97, 0xb4, 0xd1, 0xee, 0x0b, + 0x28, 0x45, 0x62, 0x7f, 0x9c, 0xb9, 0xd6, 0xf3, + 0x10, 0x2d, 0x4a, 0x67, 0x84, 0xa1, 0xbe, 0xdb, + 0xf8, 0x15, 0x32, 0x4f, 0x6c, 0x89, 0xa6, 0xc3, + 0xe0, 0xfd, 0x1a, 0x37, 0x54, 0x71, 0x8e, 0xab, + 0xc8, 0xe5, 0x02, 0x1f, 0x3c, 0x59, 0x76, 0x93, + 0xb0, 0xcd, 0xea, 0x07, 0x24, 0x41, 0x5e, 0x7b, + 0x98, 0xb5, 0xd2, 0xef, 0x0c, 0x29, 0x46, 0x63, + 0x80, 0x9d, 0xba, 0xd7, 0xf4, 0x11, 0x2e, 0x4b, + 0x68, 0x85, 0xa2, 0xbf, 0xdc, 0xf9, 0x16, 0x33, + 0x50, 0x6d, 0x8a, 0xa7, 0xc4, 0xe1, 0xfe, 0x1b, + 0x38, 0x55, 0x72, 0x8f, 0xac, 0xc9, 0xe6, 0x03, + 0x20, 0x3d, 0x5a, 0x77, 0x94, 0xb1, 0xce, 0xeb, + 0x08, 0x25, 0x42, 0x5f, 0x7c, 0x99, 0xb6, 0xd3, + 0xf0, 0x0d, 0x2a, 0x47, 0x64, 0x81, 0x9e, 0xbb, + 0xd8, 0xf5, 0x12, 0x2f, 0x4c, 0x69, 0x86, 0xa3, + 0xc0, 0xdd, 0xfa, 0x17, 0x34, 0x51, 0x6e, 0x8b, + 0xa8, 0xc5, 0xe2, 0xff, 0x1c, 0x39, 0x56, 0x73, + 0x90, 0xad, 0xca, 0xe7, 0x04, 0x21, 0x3e, 0x5b, + 0x78, 0x95, 0xb2, 0xcf, 0xec, 0x09, 0x26, 0x43, + 0x60, 0x7d, 0x9a, 0xb7, 0xd4, 0xf1, 0x0e, 0x2b, + 0x48, 0x65, 0x82, 0x9f, 0xbc, 0xd9, 0xf6, 0x13, + 0x30, 0x4d, 0x6a, 0x87, 0xa4, 0xc1, 0xde, 0xfb, + 0x18, 0x35, 0x52, 0x6f, 0x8c, 0xa9, 0xc6, 0xe3, + 0x00, 0x1f, 0x3e, 0x5d, 0x7c, 0x9b, 0xba, 0xd9, + 0xf8, 0x17, 0x36, 0x55, 0x74, 0x93, 0xb2, 0xd1, + 0xf0, 0x0f, 0x2e, 0x4d, 0x6c, 0x8b, 0xaa, 0xc9, + 0xe8, 0x07, 0x26, 0x45, 0x64, 0x83, 0xa2, 0xc1, + 0xe0, 0xff, 0x1e, 0x3d, 0x5c, 0x7b, 0x9a, 0xb9, + 0xd8, 0xf7, 0x16, 0x35, 0x54, 0x73, 0x92, 0xb1, + 0xd0, 0xef, 0x0e, 0x2d, 0x4c, 0x6b, 0x8a, 0xa9, + 0xc8, 0xe7, 0x06, 0x25, 0x44, 0x63, 0x82, 0xa1, + 0xc0, 0xdf, 0xfe, 0x1d, 0x3c, 0x5b, 0x7a, 0x99, + 0xb8, 0xd7, 0xf6, 0x15, 0x34, 0x53, 0x72, 0x91, + 0xb0, 0xcf, 0xee, 0x0d, 0x2c, 0x4b, 0x6a, 0x89, + 0xa8, 0xc7, 0xe6, 0x05, 0x24, 0x43, 0x62, 0x81, + 0xa0, 0xbf, 0xde, 0xfd, 0x1c, 0x3b, 0x5a, 0x79, + 0x98, 0xb7, 0xd6, 0xf5, 0x14, 0x33, 0x52, 0x71, + 0x90, 0xaf, 0xce, 0xed, 0x0c, 0x2b, 0x4a, 0x69, + 0x88, 0xa7, 0xc6, 0xe5, 0x04, 0x23, 0x42, 0x61, + 0x80, 0x9f, 0xbe, 0xdd, 0xfc, 0x1b, 0x3a, 0x59, + 0x78, 0x97, 0xb6, 0xd5, 0xf4, 0x13, 0x32, 0x51, + 0x70, 0x8f, 0xae, 0xcd, 0xec, 0x0b, 0x2a, 0x49, + 0x68, 0x87, 0xa6, 0xc5, 0xe4, 0x03, 0x22, 0x41, + 0x60, 0x7f, 0x9e, 0xbd, 0xdc, 0xfb, 0x1a, 0x39, + 0x58, 0x77, 0x96, 0xb5, 0xd4, 0xf3, 0x12, 0x31, + 0x50, 0x6f, 0x8e, 0xad, 0xcc, 0xeb, 0x0a, 0x29, + 0x48, 0x67, 0x86, 0xa5, 0xc4, 0xe3, 0x02, 0x21, + 0x40, 0x5f, 0x7e, 0x9d, 0xbc, 0xdb, 0xfa, 0x19, + 0x38, 0x57, 0x76, 0x95, 0xb4, 0xd3, 0xf2, 0x11, + 0x30, 0x4f, 0x6e, 0x8d, 0xac, 0xcb, 0xea, 0x09, + 0x28, 0x47, 0x66, 0x85, 0xa4, 0xc3, 0xe2, 0x01, + 0x20, 0x3f, 0x5e, 0x7d, 0x9c, 0xbb, 0xda, 0xf9, + 0x18, 0x37, 0x56, 0x75, 0x94, 0xb3, 0xd2, 0xf1, + 0x10, 0x2f, 0x4e, 0x6d, 0x8c, 0xab, 0xca, 0xe9, + 0x08, 0x27, 0x46, 0x65, 0x84, 0xa3, 0xc2, 0xe1, + 0x00, 0x21, 0x42, 0x63, + }, + .ilen = 4100, + .result = { + 0xf0, 0x5c, 0x74, 0xad, 0x4e, 0xbc, 0x99, 0xe2, + 0xae, 0xff, 0x91, 0x3a, 0x44, 0xcf, 0x38, 0x32, + 0x1e, 0xad, 0xa7, 0xcd, 0xa1, 0x39, 0x95, 0xaa, + 0x10, 0xb1, 0xb3, 0x2e, 0x04, 0x31, 0x8f, 0x86, + 0xf2, 0x62, 0x74, 0x70, 0x0c, 0xa4, 0x46, 0x08, + 0xa8, 0xb7, 0x99, 0xa8, 0xe9, 0xd2, 0x73, 0x79, + 0x7e, 0x6e, 0xd4, 0x8f, 0x1e, 0xc7, 0x8e, 0x31, + 0x0b, 0xfa, 0x4b, 0xce, 0xfd, 0xf3, 0x57, 0x71, + 0xe9, 0x46, 0x03, 0xa5, 0x3d, 0x34, 0x00, 0xe2, + 0x18, 0xff, 0x75, 0x6d, 0x06, 0x2d, 0x00, 0xab, + 0xb9, 0x3e, 0x6c, 0x59, 0xc5, 0x84, 0x06, 0xb5, + 0x8b, 0xd0, 0x89, 0x9c, 0x4a, 0x79, 0x16, 0xc6, + 0x3d, 0x74, 0x54, 0xfa, 0x44, 0xcd, 0x23, 0x26, + 0x5c, 0xcf, 0x7e, 0x28, 0x92, 0x32, 0xbf, 0xdf, + 0xa7, 0x20, 0x3c, 0x74, 0x58, 0x2a, 0x9a, 0xde, + 0x61, 0x00, 0x1c, 0x4f, 0xff, 0x59, 0xc4, 0x22, + 0xac, 0x3c, 0xd0, 0xe8, 0x6c, 0xf9, 0x97, 0x1b, + 0x58, 0x9b, 0xad, 0x71, 0xe8, 0xa9, 0xb5, 0x0d, + 0xee, 0x2f, 0x04, 0x1f, 0x7f, 0xbc, 0x99, 0xee, + 0x84, 0xff, 0x42, 0x60, 0xdc, 0x3a, 0x18, 0xa5, + 0x81, 0xf9, 0xef, 0xdc, 0x7a, 0x0f, 0x65, 0x41, + 0x2f, 0xa3, 0xd3, 0xf9, 0xc2, 0xcb, 0xc0, 0x4d, + 0x8f, 0xd3, 0x76, 0x96, 0xad, 0x49, 0x6d, 0x38, + 0x3d, 0x39, 0x0b, 0x6c, 0x80, 0xb7, 0x54, 0x69, + 0xf0, 0x2c, 0x90, 0x02, 0x29, 0x0d, 0x1c, 0x12, + 0xad, 0x55, 0xc3, 0x8b, 0x68, 0xd9, 0xcc, 0xb3, + 0xb2, 0x64, 0x33, 0x90, 0x5e, 0xca, 0x4b, 0xe2, + 0xfb, 0x75, 0xdc, 0x63, 0xf7, 0x9f, 0x82, 0x74, + 0xf0, 0xc9, 0xaa, 0x7f, 0xe9, 0x2a, 0x9b, 0x33, + 0xbc, 0x88, 0x00, 0x7f, 0xca, 0xb2, 0x1f, 0x14, + 0xdb, 0xc5, 0x8e, 0x7b, 0x11, 0x3c, 0x3e, 0x08, + 0xf3, 0x83, 0xe8, 0xe0, 0x94, 0x86, 0x2e, 0x92, + 0x78, 0x6b, 0x01, 0xc9, 0xc7, 0x83, 0xba, 0x21, + 0x6a, 0x25, 0x15, 0x33, 0x4e, 0x45, 0x08, 0xec, + 0x35, 0xdb, 0xe0, 0x6e, 0x31, 0x51, 0x79, 0xa9, + 0x42, 0x44, 0x65, 0xc1, 0xa0, 0xf1, 0xf9, 0x2a, + 0x70, 0xd5, 0xb6, 0xc6, 0xc1, 0x8c, 0x39, 0xfc, + 0x25, 0xa6, 0x55, 0xd9, 0xdd, 0x2d, 0x4c, 0xec, + 0x49, 0xc6, 0xeb, 0x0e, 0xa8, 0x25, 0x2a, 0x16, + 0x1b, 0x66, 0x84, 0xda, 0xe2, 0x92, 0xe5, 0xc0, + 0xc8, 0x53, 0x07, 0xaf, 0x80, 0x84, 0xec, 0xfd, + 0xcd, 0xd1, 0x6e, 0xcd, 0x6f, 0x6a, 0xf5, 0x36, + 0xc5, 0x15, 0xe5, 0x25, 0x7d, 0x77, 0xd1, 0x1a, + 0x93, 0x36, 0xa9, 0xcf, 0x7c, 0xa4, 0x54, 0x4a, + 0x06, 0x51, 0x48, 0x4e, 0xf6, 0x59, 0x87, 0xd2, + 0x04, 0x02, 0xef, 0xd3, 0x44, 0xde, 0x76, 0x31, + 0xb3, 0x34, 0x17, 0x1b, 0x9d, 0x66, 0x11, 0x9f, + 0x1e, 0xcc, 0x17, 0xe9, 0xc7, 0x3c, 0x1b, 0xe7, + 0xcb, 0x50, 0x08, 0xfc, 0xdc, 0x2b, 0x24, 0xdb, + 0x65, 0x83, 0xd0, 0x3b, 0xe3, 0x30, 0xea, 0x94, + 0x6c, 0xe7, 0xe8, 0x35, 0x32, 0xc7, 0xdb, 0x64, + 0xb4, 0x01, 0xab, 0x36, 0x2c, 0x77, 0x13, 0xaf, + 0xf8, 0x2b, 0x88, 0x3f, 0x54, 0x39, 0xc4, 0x44, + 0xfe, 0xef, 0x6f, 0x68, 0x34, 0xbe, 0x0f, 0x05, + 0x16, 0x6d, 0xf6, 0x0a, 0x30, 0xe7, 0xe3, 0xed, + 0xc4, 0xde, 0x3c, 0x1b, 0x13, 0xd8, 0xdb, 0xfe, + 0x41, 0x62, 0xe5, 0x28, 0xd4, 0x8d, 0xa3, 0xc7, + 0x93, 0x97, 0xc6, 0x48, 0x45, 0x1d, 0x9f, 0x83, + 0xdf, 0x4b, 0x40, 0x3e, 0x42, 0x25, 0x87, 0x80, + 0x4c, 0x7d, 0xa8, 0xd4, 0x98, 0x23, 0x95, 0x75, + 0x41, 0x8c, 0xda, 0x41, 0x9b, 0xd4, 0xa7, 0x06, + 0xb5, 0xf1, 0x71, 0x09, 0x53, 0xbe, 0xca, 0xbf, + 0x32, 0x03, 0xed, 0xf0, 0x50, 0x1c, 0x56, 0x39, + 0x5b, 0xa4, 0x75, 0x18, 0xf7, 0x9b, 0x58, 0xef, + 0x53, 0xfc, 0x2a, 0x38, 0x23, 0x15, 0x75, 0xcd, + 0x45, 0xe5, 0x5a, 0x82, 0x55, 0xba, 0x21, 0xfa, + 0xd4, 0xbd, 0xc6, 0x94, 0x7c, 0xc5, 0x80, 0x12, + 0xf7, 0x4b, 0x32, 0xc4, 0x9a, 0x82, 0xd8, 0x28, + 0x8f, 0xd9, 0xc2, 0x0f, 0x60, 0x03, 0xbe, 0x5e, + 0x21, 0xd6, 0x5f, 0x58, 0xbf, 0x5c, 0xb1, 0x32, + 0x82, 0x8d, 0xa9, 0xe5, 0xf2, 0x66, 0x1a, 0xc0, + 0xa0, 0xbc, 0x58, 0x2f, 0x71, 0xf5, 0x2f, 0xed, + 0xd1, 0x26, 0xb9, 0xd8, 0x49, 0x5a, 0x07, 0x19, + 0x01, 0x7c, 0x59, 0xb0, 0xf8, 0xa4, 0xb7, 0xd3, + 0x7b, 0x1a, 0x8c, 0x38, 0xf4, 0x50, 0xa4, 0x59, + 0xb0, 0xcc, 0x41, 0x0b, 0x88, 0x7f, 0xe5, 0x31, + 0xb3, 0x42, 0xba, 0xa2, 0x7e, 0xd4, 0x32, 0x71, + 0x45, 0x87, 0x48, 0xa9, 0xc2, 0xf2, 0x89, 0xb3, + 0xe4, 0xa7, 0x7e, 0x52, 0x15, 0x61, 0xfa, 0xfe, + 0xc9, 0xdd, 0x81, 0xeb, 0x13, 0xab, 0xab, 0xc3, + 0x98, 0x59, 0xd8, 0x16, 0x3d, 0x14, 0x7a, 0x1c, + 0x3c, 0x41, 0x9a, 0x16, 0x16, 0x9b, 0xd2, 0xd2, + 0x69, 0x3a, 0x29, 0x23, 0xac, 0x86, 0x32, 0xa5, + 0x48, 0x9c, 0x9e, 0xf3, 0x47, 0x77, 0x81, 0x70, + 0x24, 0xe8, 0x85, 0xd2, 0xf5, 0xb5, 0xfa, 0xff, + 0x59, 0x6a, 0xd3, 0x50, 0x59, 0x43, 0x59, 0xde, + 0xd9, 0xf1, 0x55, 0xa5, 0x0c, 0xc3, 0x1a, 0x1a, + 0x18, 0x34, 0x0d, 0x1a, 0x63, 0x33, 0xed, 0x10, + 0xe0, 0x1d, 0x2a, 0x18, 0xd2, 0xc0, 0x54, 0xa8, + 0xca, 0xb5, 0x9a, 0xd3, 0xdd, 0xca, 0x45, 0x84, + 0x50, 0xe7, 0x0f, 0xfe, 0xa4, 0x99, 0x5a, 0xbe, + 0x43, 0x2d, 0x9a, 0xcb, 0x92, 0x3f, 0x5a, 0x1d, + 0x85, 0xd8, 0xc9, 0xdf, 0x68, 0xc9, 0x12, 0x80, + 0x56, 0x0c, 0xdc, 0x00, 0xdc, 0x3a, 0x7d, 0x9d, + 0xa3, 0xa2, 0xe8, 0x4d, 0xbf, 0xf9, 0x70, 0xa0, + 0xa4, 0x13, 0x4f, 0x6b, 0xaf, 0x0a, 0x89, 0x7f, + 0xda, 0xf0, 0xbf, 0x9b, 0xc8, 0x1d, 0xe5, 0xf8, + 0x2e, 0x8b, 0x07, 0xb5, 0x73, 0x1b, 0xcc, 0xa2, + 0xa6, 0xad, 0x30, 0xbc, 0x78, 0x3c, 0x5b, 0x10, + 0xfa, 0x5e, 0x62, 0x2d, 0x9e, 0x64, 0xb3, 0x33, + 0xce, 0xf9, 0x1f, 0x86, 0xe7, 0x8b, 0xa2, 0xb8, + 0xe8, 0x99, 0x57, 0x8c, 0x11, 0xed, 0x66, 0xd9, + 0x3c, 0x72, 0xb9, 0xc3, 0xe6, 0x4e, 0x17, 0x3a, + 0x6a, 0xcb, 0x42, 0x24, 0x06, 0xed, 0x3e, 0x4e, + 0xa3, 0xe8, 0x6a, 0x94, 0xda, 0x0d, 0x4e, 0xd5, + 0x14, 0x19, 0xcf, 0xb6, 0x26, 0xd8, 0x2e, 0xcc, + 0x64, 0x76, 0x38, 0x49, 0x4d, 0xfe, 0x30, 0x6d, + 0xe4, 0xc8, 0x8c, 0x7b, 0xc4, 0xe0, 0x35, 0xba, + 0x22, 0x6e, 0x76, 0xe1, 0x1a, 0xf2, 0x53, 0xc3, + 0x28, 0xa2, 0x82, 0x1f, 0x61, 0x69, 0xad, 0xc1, + 0x7b, 0x28, 0x4b, 0x1e, 0x6c, 0x85, 0x95, 0x9b, + 0x51, 0xb5, 0x17, 0x7f, 0x12, 0x69, 0x8c, 0x24, + 0xd5, 0xc7, 0x5a, 0x5a, 0x11, 0x54, 0xff, 0x5a, + 0xf7, 0x16, 0xc3, 0x91, 0xa6, 0xf0, 0xdc, 0x0a, + 0xb6, 0xa7, 0x4a, 0x0d, 0x7a, 0x58, 0xfe, 0xa5, + 0xf5, 0xcb, 0x8f, 0x7b, 0x0e, 0xea, 0x57, 0xe7, + 0xbd, 0x79, 0xd6, 0x1c, 0x88, 0x23, 0x6c, 0xf2, + 0x4d, 0x29, 0x77, 0x53, 0x35, 0x6a, 0x00, 0x8d, + 0xcd, 0xa3, 0x58, 0xbe, 0x77, 0x99, 0x18, 0xf8, + 0xe6, 0xe1, 0x8f, 0xe9, 0x37, 0x8f, 0xe3, 0xe2, + 0x5a, 0x8a, 0x93, 0x25, 0xaf, 0xf3, 0x78, 0x80, + 0xbe, 0xa6, 0x1b, 0xc6, 0xac, 0x8b, 0x1c, 0x91, + 0x58, 0xe1, 0x9f, 0x89, 0x35, 0x9d, 0x1d, 0x21, + 0x29, 0x9f, 0xf4, 0x99, 0x02, 0x27, 0x0f, 0xa8, + 0x4f, 0x79, 0x94, 0x2b, 0x33, 0x2c, 0xda, 0xa2, + 0x26, 0x39, 0x83, 0x94, 0xef, 0x27, 0xd8, 0x53, + 0x8f, 0x66, 0x0d, 0xe4, 0x41, 0x7d, 0x34, 0xcd, + 0x43, 0x7c, 0x95, 0x0a, 0x53, 0xef, 0x66, 0xda, + 0x7e, 0x9b, 0xf3, 0x93, 0xaf, 0xd0, 0x73, 0x71, + 0xba, 0x40, 0x9b, 0x74, 0xf8, 0xd7, 0xd7, 0x41, + 0x6d, 0xaf, 0x72, 0x9c, 0x8d, 0x21, 0x87, 0x3c, + 0xfd, 0x0a, 0x90, 0xa9, 0x47, 0x96, 0x9e, 0xd3, + 0x88, 0xee, 0x73, 0xcf, 0x66, 0x2f, 0x52, 0x56, + 0x6d, 0xa9, 0x80, 0x4c, 0xe2, 0x6f, 0x62, 0x88, + 0x3f, 0x0e, 0x54, 0x17, 0x48, 0x80, 0x5d, 0xd3, + 0xc3, 0xda, 0x25, 0x3d, 0xa1, 0xc8, 0xcb, 0x9f, + 0x9b, 0x70, 0xb3, 0xa1, 0xeb, 0x04, 0x52, 0xa1, + 0xf2, 0x22, 0x0f, 0xfc, 0xc8, 0x18, 0xfa, 0xf9, + 0x85, 0x9c, 0xf1, 0xac, 0xeb, 0x0c, 0x02, 0x46, + 0x75, 0xd2, 0xf5, 0x2c, 0xe3, 0xd2, 0x59, 0x94, + 0x12, 0xf3, 0x3c, 0xfc, 0xd7, 0x92, 0xfa, 0x36, + 0xba, 0x61, 0x34, 0x38, 0x7c, 0xda, 0x48, 0x3e, + 0x08, 0xc9, 0x39, 0x23, 0x5e, 0x02, 0x2c, 0x1a, + 0x18, 0x7e, 0xb4, 0xd9, 0xfd, 0x9e, 0x40, 0x02, + 0xb1, 0x33, 0x37, 0x32, 0xe7, 0xde, 0xd6, 0xd0, + 0x7c, 0x58, 0x65, 0x4b, 0xf8, 0x34, 0x27, 0x9c, + 0x44, 0xb4, 0xbd, 0xe9, 0xe9, 0x4c, 0x78, 0x7d, + 0x4b, 0x9f, 0xce, 0xb1, 0xcd, 0x47, 0xa5, 0x37, + 0xe5, 0x6d, 0xbd, 0xb9, 0x43, 0x94, 0x0a, 0xd4, + 0xd6, 0xf9, 0x04, 0x5f, 0xb5, 0x66, 0x6c, 0x1a, + 0x35, 0x12, 0xe3, 0x36, 0x28, 0x27, 0x36, 0x58, + 0x01, 0x2b, 0x79, 0xe4, 0xba, 0x6d, 0x10, 0x7d, + 0x65, 0xdf, 0x84, 0x95, 0xf4, 0xd5, 0xb6, 0x8f, + 0x2b, 0x9f, 0x96, 0x00, 0x86, 0x60, 0xf0, 0x21, + 0x76, 0xa8, 0x6a, 0x8c, 0x28, 0x1c, 0xb3, 0x6b, + 0x97, 0xd7, 0xb6, 0x53, 0x2a, 0xcc, 0xab, 0x40, + 0x9d, 0x62, 0x79, 0x58, 0x52, 0xe6, 0x65, 0xb7, + 0xab, 0x55, 0x67, 0x9c, 0x89, 0x7c, 0x03, 0xb0, + 0x73, 0x59, 0xc5, 0x81, 0xf5, 0x18, 0x17, 0x5c, + 0x89, 0xf3, 0x78, 0x35, 0x44, 0x62, 0x78, 0x72, + 0xd0, 0x96, 0xeb, 0x31, 0xe7, 0x87, 0x77, 0x14, + 0x99, 0x51, 0xf2, 0x59, 0x26, 0x9e, 0xb5, 0xa6, + 0x45, 0xfe, 0x6e, 0xbd, 0x07, 0x4c, 0x94, 0x5a, + 0xa5, 0x7d, 0xfc, 0xf1, 0x2b, 0x77, 0xe2, 0xfe, + 0x17, 0xd4, 0x84, 0xa0, 0xac, 0xb5, 0xc7, 0xda, + 0xa9, 0x1a, 0xb6, 0xf3, 0x74, 0x11, 0xb4, 0x9d, + 0xfb, 0x79, 0x2e, 0x04, 0x2d, 0x50, 0x28, 0x83, + 0xbf, 0xc6, 0x52, 0xd3, 0x34, 0xd6, 0xe8, 0x7a, + 0xb6, 0xea, 0xe7, 0xa8, 0x6c, 0x15, 0x1e, 0x2c, + 0x57, 0xbc, 0x48, 0x4e, 0x5f, 0x5c, 0xb6, 0x92, + 0xd2, 0x49, 0x77, 0x81, 0x6d, 0x90, 0x70, 0xae, + 0x98, 0xa1, 0x03, 0x0d, 0x6b, 0xb9, 0x77, 0x14, + 0xf1, 0x4e, 0x23, 0xd3, 0xf8, 0x68, 0xbd, 0xc2, + 0xfe, 0x04, 0xb7, 0x5c, 0xc5, 0x17, 0x60, 0x8f, + 0x65, 0x54, 0xa4, 0x7a, 0x42, 0xdc, 0x18, 0x0d, + 0xb5, 0xcf, 0x0f, 0xd3, 0xc7, 0x91, 0x66, 0x1b, + 0x45, 0x42, 0x27, 0x75, 0x50, 0xe5, 0xee, 0xb8, + 0x7f, 0x33, 0x2c, 0xba, 0x4a, 0x92, 0x4d, 0x2c, + 0x3c, 0xe3, 0x0d, 0x80, 0x01, 0xba, 0x0d, 0x29, + 0xd8, 0x3c, 0xe9, 0x13, 0x16, 0x57, 0xe6, 0xea, + 0x94, 0x52, 0xe7, 0x00, 0x4d, 0x30, 0xb0, 0x0f, + 0x35, 0xb8, 0xb8, 0xa7, 0xb1, 0xb5, 0x3b, 0x44, + 0xe1, 0x2f, 0xfd, 0x88, 0xed, 0x43, 0xe7, 0x52, + 0x10, 0x93, 0xb3, 0x8a, 0x30, 0x6b, 0x0a, 0xf7, + 0x23, 0xc6, 0x50, 0x9d, 0x4a, 0xb0, 0xde, 0xc3, + 0xdc, 0x9b, 0x2f, 0x01, 0x56, 0x36, 0x09, 0xc5, + 0x2f, 0x6b, 0xfe, 0xf1, 0xd8, 0x27, 0x45, 0x03, + 0x30, 0x5e, 0x5c, 0x5b, 0xb4, 0x62, 0x0e, 0x1a, + 0xa9, 0x21, 0x2b, 0x92, 0x94, 0x87, 0x62, 0x57, + 0x4c, 0x10, 0x74, 0x1a, 0xf1, 0x0a, 0xc5, 0x84, + 0x3b, 0x9e, 0x72, 0x02, 0xd7, 0xcc, 0x09, 0x56, + 0xbd, 0x54, 0xc1, 0xf0, 0xc3, 0xe3, 0xb3, 0xf8, + 0xd2, 0x0d, 0x61, 0xcb, 0xef, 0xce, 0x0d, 0x05, + 0xb0, 0x98, 0xd9, 0x8e, 0x4f, 0xf9, 0xbc, 0x93, + 0xa6, 0xea, 0xc8, 0xcf, 0x10, 0x53, 0x4b, 0xf1, + 0xec, 0xfc, 0x89, 0xf9, 0x64, 0xb0, 0x22, 0xbf, + 0x9e, 0x55, 0x46, 0x9f, 0x7c, 0x50, 0x8e, 0x84, + 0x54, 0x20, 0x98, 0xd7, 0x6c, 0x40, 0x1e, 0xdb, + 0x69, 0x34, 0x78, 0x61, 0x24, 0x21, 0x9c, 0x8a, + 0xb3, 0x62, 0x31, 0x8b, 0x6e, 0xf5, 0x2a, 0x35, + 0x86, 0x13, 0xb1, 0x6c, 0x64, 0x2e, 0x41, 0xa5, + 0x05, 0xf2, 0x42, 0xba, 0xd2, 0x3a, 0x0d, 0x8e, + 0x8a, 0x59, 0x94, 0x3c, 0xcf, 0x36, 0x27, 0x82, + 0xc2, 0x45, 0xee, 0x58, 0xcd, 0x88, 0xb4, 0xec, + 0xde, 0xb2, 0x96, 0x0a, 0xaf, 0x38, 0x6f, 0x88, + 0xd7, 0xd8, 0xe1, 0xdf, 0xb9, 0x96, 0xa9, 0x0a, + 0xb1, 0x95, 0x28, 0x86, 0x20, 0xe9, 0x17, 0x49, + 0xa2, 0x29, 0x38, 0xaa, 0xa5, 0xe9, 0x6e, 0xf1, + 0x19, 0x27, 0xc0, 0xd5, 0x2a, 0x22, 0xc3, 0x0b, + 0xdb, 0x7c, 0x73, 0x10, 0xb9, 0xba, 0x89, 0x76, + 0x54, 0xae, 0x7d, 0x71, 0xb3, 0x93, 0xf6, 0x32, + 0xe6, 0x47, 0x43, 0x55, 0xac, 0xa0, 0x0d, 0xc2, + 0x93, 0x27, 0x4a, 0x8e, 0x0e, 0x74, 0x15, 0xc7, + 0x0b, 0x85, 0xd9, 0x0c, 0xa9, 0x30, 0x7a, 0x3e, + 0xea, 0x8f, 0x85, 0x6d, 0x3a, 0x12, 0x4f, 0x72, + 0x69, 0x58, 0x7a, 0x80, 0xbb, 0xb5, 0x97, 0xf3, + 0xcf, 0x70, 0xd2, 0x5d, 0xdd, 0x4d, 0x21, 0x79, + 0x54, 0x4d, 0xe4, 0x05, 0xe8, 0xbd, 0xc2, 0x62, + 0xb1, 0x3b, 0x77, 0x1c, 0xd6, 0x5c, 0xf3, 0xa0, + 0x79, 0x00, 0xa8, 0x6c, 0x29, 0xd9, 0x18, 0x24, + 0x36, 0xa2, 0x46, 0xc0, 0x96, 0x65, 0x7f, 0xbd, + 0x2a, 0xed, 0x36, 0x16, 0x0c, 0xaa, 0x9f, 0xf4, + 0xc5, 0xb4, 0xe2, 0x12, 0xed, 0x69, 0xed, 0x4f, + 0x26, 0x2c, 0x39, 0x52, 0x89, 0x98, 0xe7, 0x2c, + 0x99, 0xa4, 0x9e, 0xa3, 0x9b, 0x99, 0x46, 0x7a, + 0x3a, 0xdc, 0xa8, 0x59, 0xa3, 0xdb, 0xc3, 0x3b, + 0x95, 0x0d, 0x3b, 0x09, 0x6e, 0xee, 0x83, 0x5d, + 0x32, 0x4d, 0xed, 0xab, 0xfa, 0x98, 0x14, 0x4e, + 0xc3, 0x15, 0x45, 0x53, 0x61, 0xc4, 0x93, 0xbd, + 0x90, 0xf4, 0x99, 0x95, 0x4c, 0xe6, 0x76, 0x92, + 0x29, 0x90, 0x46, 0x30, 0x92, 0x69, 0x7d, 0x13, + 0xf2, 0xa5, 0xcd, 0x69, 0x49, 0x44, 0xb2, 0x0f, + 0x63, 0x40, 0x36, 0x5f, 0x09, 0xe2, 0x78, 0xf8, + 0x91, 0xe3, 0xe2, 0xfa, 0x10, 0xf7, 0xc8, 0x24, + 0xa8, 0x89, 0x32, 0x5c, 0x37, 0x25, 0x1d, 0xb2, + 0xea, 0x17, 0x8a, 0x0a, 0xa9, 0x64, 0xc3, 0x7c, + 0x3c, 0x7c, 0xbd, 0xc6, 0x79, 0x34, 0xe7, 0xe2, + 0x85, 0x8e, 0xbf, 0xf8, 0xde, 0x92, 0xa0, 0xae, + 0x20, 0xc4, 0xf6, 0xbb, 0x1f, 0x38, 0x19, 0x0e, + 0xe8, 0x79, 0x9c, 0xa1, 0x23, 0xe9, 0x54, 0x7e, + 0x37, 0x2f, 0xe2, 0x94, 0x32, 0xaf, 0xa0, 0x23, + 0x49, 0xe4, 0xc0, 0xb3, 0xac, 0x00, 0x8f, 0x36, + 0x05, 0xc4, 0xa6, 0x96, 0xec, 0x05, 0x98, 0x4f, + 0x96, 0x67, 0x57, 0x1f, 0x20, 0x86, 0x1b, 0x2d, + 0x69, 0xe4, 0x29, 0x93, 0x66, 0x5f, 0xaf, 0x6b, + 0x88, 0x26, 0x2c, 0x67, 0x02, 0x4b, 0x52, 0xd0, + 0x83, 0x7a, 0x43, 0x1f, 0xc0, 0x71, 0x15, 0x25, + 0x77, 0x65, 0x08, 0x60, 0x11, 0x76, 0x4c, 0x8d, + 0xed, 0xa9, 0x27, 0xc6, 0xb1, 0x2a, 0x2c, 0x6a, + 0x4a, 0x97, 0xf5, 0xc6, 0xb7, 0x70, 0x42, 0xd3, + 0x03, 0xd1, 0x24, 0x95, 0xec, 0x6d, 0xab, 0x38, + 0x72, 0xce, 0xe2, 0x8b, 0x33, 0xd7, 0x51, 0x09, + 0xdc, 0x45, 0xe0, 0x09, 0x96, 0x32, 0xf3, 0xc4, + 0x84, 0xdc, 0x73, 0x73, 0x2d, 0x1b, 0x11, 0x98, + 0xc5, 0x0e, 0x69, 0x28, 0x94, 0xc7, 0xb5, 0x4d, + 0xc8, 0x8a, 0xd0, 0xaa, 0x13, 0x2e, 0x18, 0x74, + 0xdd, 0xd1, 0x1e, 0xf3, 0x90, 0xe8, 0xfc, 0x9a, + 0x72, 0x4a, 0x0e, 0xd1, 0xe4, 0xfb, 0x0d, 0x96, + 0xd1, 0x0c, 0x79, 0x85, 0x1b, 0x1c, 0xfe, 0xe1, + 0x62, 0x8f, 0x7a, 0x73, 0x32, 0xab, 0xc8, 0x18, + 0x69, 0xe3, 0x34, 0x30, 0xdf, 0x13, 0xa6, 0xe5, + 0xe8, 0x0e, 0x67, 0x7f, 0x81, 0x11, 0xb4, 0x60, + 0xc7, 0xbd, 0x79, 0x65, 0x50, 0xdc, 0xc4, 0x5b, + 0xde, 0x39, 0xa4, 0x01, 0x72, 0x63, 0xf3, 0xd1, + 0x64, 0x4e, 0xdf, 0xfc, 0x27, 0x92, 0x37, 0x0d, + 0x57, 0xcd, 0x11, 0x4f, 0x11, 0x04, 0x8e, 0x1d, + 0x16, 0xf7, 0xcd, 0x92, 0x9a, 0x99, 0x30, 0x14, + 0xf1, 0x7c, 0x67, 0x1b, 0x1f, 0x41, 0x0b, 0xe8, + 0x32, 0xe8, 0xb8, 0xc1, 0x4f, 0x54, 0x86, 0x4f, + 0xe5, 0x79, 0x81, 0x73, 0xcd, 0x43, 0x59, 0x68, + 0x73, 0x02, 0x3b, 0x78, 0x21, 0x72, 0x43, 0x00, + 0x49, 0x17, 0xf7, 0x00, 0xaf, 0x68, 0x24, 0x53, + 0x05, 0x0a, 0xc3, 0x33, 0xe0, 0x33, 0x3f, 0x69, + 0xd2, 0x84, 0x2f, 0x0b, 0xed, 0xde, 0x04, 0xf4, + 0x11, 0x94, 0x13, 0x69, 0x51, 0x09, 0x28, 0xde, + 0x57, 0x5c, 0xef, 0xdc, 0x9a, 0x49, 0x1c, 0x17, + 0x97, 0xf3, 0x96, 0xc1, 0x7f, 0x5d, 0x2e, 0x7d, + 0x55, 0xb8, 0xb3, 0x02, 0x09, 0xb3, 0x1f, 0xe7, + 0xc9, 0x8d, 0xa3, 0x36, 0x34, 0x8a, 0x77, 0x13, + 0x30, 0x63, 0x4c, 0xa5, 0xcd, 0xc3, 0xe0, 0x7e, + 0x05, 0xa1, 0x7b, 0x0c, 0xcb, 0x74, 0x47, 0x31, + 0x62, 0x03, 0x43, 0xf1, 0x87, 0xb4, 0xb0, 0x85, + 0x87, 0x8e, 0x4b, 0x25, 0xc7, 0xcf, 0xae, 0x4b, + 0x36, 0x46, 0x3e, 0x62, 0xbc, 0x6f, 0xeb, 0x5f, + 0x73, 0xac, 0xe6, 0x07, 0xee, 0xc1, 0xa1, 0xd6, + 0xc4, 0xab, 0xc9, 0xd6, 0x89, 0x45, 0xe1, 0xf1, + 0x04, 0x4e, 0x1a, 0x6f, 0xbb, 0x4f, 0x3a, 0xa3, + 0xa0, 0xcb, 0xa3, 0x0a, 0xd8, 0x71, 0x35, 0x55, + 0xe4, 0xbc, 0x2e, 0x04, 0x06, 0xe6, 0xff, 0x5b, + 0x1c, 0xc0, 0x11, 0x7c, 0xc5, 0x17, 0xf3, 0x38, + 0xcf, 0xe9, 0xba, 0x0f, 0x0e, 0xef, 0x02, 0xc2, + 0x8d, 0xc6, 0xbc, 0x4b, 0x67, 0x20, 0x95, 0xd7, + 0x2c, 0x45, 0x5b, 0x86, 0x44, 0x8c, 0x6f, 0x2e, + 0x7e, 0x9f, 0x1c, 0x77, 0xba, 0x6b, 0x0e, 0xa3, + 0x69, 0xdc, 0xab, 0x24, 0x57, 0x60, 0x47, 0xc1, + 0xd1, 0xa5, 0x9d, 0x23, 0xe6, 0xb1, 0x37, 0xfe, + 0x93, 0xd2, 0x4c, 0x46, 0xf9, 0x0c, 0xc6, 0xfb, + 0xd6, 0x9d, 0x99, 0x69, 0xab, 0x7a, 0x07, 0x0c, + 0x65, 0xe7, 0xc4, 0x08, 0x96, 0xe2, 0xa5, 0x01, + 0x3f, 0x46, 0x07, 0x05, 0x7e, 0xe8, 0x9a, 0x90, + 0x50, 0xdc, 0xe9, 0x7a, 0xea, 0xa1, 0x39, 0x6e, + 0x66, 0xe4, 0x6f, 0xa5, 0x5f, 0xb2, 0xd9, 0x5b, + 0xf5, 0xdb, 0x2a, 0x32, 0xf0, 0x11, 0x6f, 0x7c, + 0x26, 0x10, 0x8f, 0x3d, 0x80, 0xe9, 0x58, 0xf7, + 0xe0, 0xa8, 0x57, 0xf8, 0xdb, 0x0e, 0xce, 0x99, + 0x63, 0x19, 0x3d, 0xd5, 0xec, 0x1b, 0x77, 0x69, + 0x98, 0xf6, 0xe4, 0x5f, 0x67, 0x17, 0x4b, 0x09, + 0x85, 0x62, 0x82, 0x70, 0x18, 0xe2, 0x9a, 0x78, + 0xe2, 0x62, 0xbd, 0xb4, 0xf1, 0x42, 0xc6, 0xfb, + 0x08, 0xd0, 0xbd, 0xeb, 0x4e, 0x09, 0xf2, 0xc8, + 0x1e, 0xdc, 0x3d, 0x32, 0x21, 0x56, 0x9c, 0x4f, + 0x35, 0xf3, 0x61, 0x06, 0x72, 0x84, 0xc4, 0x32, + 0xf2, 0xf1, 0xfa, 0x0b, 0x2f, 0xc3, 0xdb, 0x02, + 0x04, 0xc2, 0xde, 0x57, 0x64, 0x60, 0x8d, 0xcf, + 0xcb, 0x86, 0x5d, 0x97, 0x3e, 0xb1, 0x9c, 0x01, + 0xd6, 0x28, 0x8f, 0x99, 0xbc, 0x46, 0xeb, 0x05, + 0xaf, 0x7e, 0xb8, 0x21, 0x2a, 0x56, 0x85, 0x1c, + 0xb3, 0x71, 0xa0, 0xde, 0xca, 0x96, 0xf1, 0x78, + 0x49, 0xa2, 0x99, 0x81, 0x80, 0x5c, 0x01, 0xf5, + 0xa0, 0xa2, 0x56, 0x63, 0xe2, 0x70, 0x07, 0xa5, + 0x95, 0xd6, 0x85, 0xeb, 0x36, 0x9e, 0xa9, 0x51, + 0x66, 0x56, 0x5f, 0x1d, 0x02, 0x19, 0xe2, 0xf6, + 0x4f, 0x73, 0x38, 0x09, 0x75, 0x64, 0x48, 0xe0, + 0xf1, 0x7e, 0x0e, 0xe8, 0x9d, 0xf9, 0xed, 0x94, + 0xfe, 0x16, 0x26, 0x62, 0x49, 0x74, 0xf4, 0xb0, + 0xd4, 0xa9, 0x6c, 0xb0, 0xfd, 0x53, 0xe9, 0x81, + 0xe0, 0x7a, 0xbf, 0xcf, 0xb5, 0xc4, 0x01, 0x81, + 0x79, 0x99, 0x77, 0x01, 0x3b, 0xe9, 0xa2, 0xb6, + 0xe6, 0x6a, 0x8a, 0x9e, 0x56, 0x1c, 0x8d, 0x1e, + 0x8f, 0x06, 0x55, 0x2c, 0x6c, 0xdc, 0x92, 0x87, + 0x64, 0x3b, 0x4b, 0x19, 0xa1, 0x13, 0x64, 0x1d, + 0x4a, 0xe9, 0xc0, 0x00, 0xb8, 0x95, 0xef, 0x6b, + 0x1a, 0x86, 0x6d, 0x37, 0x52, 0x02, 0xc2, 0xe0, + 0xc8, 0xbb, 0x42, 0x0c, 0x02, 0x21, 0x4a, 0xc9, + 0xef, 0xa0, 0x54, 0xe4, 0x5e, 0x16, 0x53, 0x81, + 0x70, 0x62, 0x10, 0xaf, 0xde, 0xb8, 0xb5, 0xd3, + 0xe8, 0x5e, 0x6c, 0xc3, 0x8a, 0x3e, 0x18, 0x07, + 0xf2, 0x2f, 0x7d, 0xa7, 0xe1, 0x3d, 0x4e, 0xb4, + 0x26, 0xa7, 0xa3, 0x93, 0x86, 0xb2, 0x04, 0x1e, + 0x53, 0x5d, 0x86, 0xd6, 0xde, 0x65, 0xca, 0xe3, + 0x4e, 0xc1, 0xcf, 0xef, 0xc8, 0x70, 0x1b, 0x83, + 0x13, 0xdd, 0x18, 0x8b, 0x0d, 0x76, 0xd2, 0xf6, + 0x37, 0x7a, 0x93, 0x7a, 0x50, 0x11, 0x9f, 0x96, + 0x86, 0x25, 0xfd, 0xac, 0xdc, 0xbe, 0x18, 0x93, + 0x19, 0x6b, 0xec, 0x58, 0x4f, 0xb9, 0x75, 0xa7, + 0xdd, 0x3f, 0x2f, 0xec, 0xc8, 0x5a, 0x84, 0xab, + 0xd5, 0xe4, 0x8a, 0x07, 0xf6, 0x4d, 0x23, 0xd6, + 0x03, 0xfb, 0x03, 0x6a, 0xea, 0x66, 0xbf, 0xd4, + 0xb1, 0x34, 0xfb, 0x78, 0xe9, 0x55, 0xdc, 0x7c, + 0x3d, 0x9c, 0xe5, 0x9a, 0xac, 0xc3, 0x7a, 0x80, + 0x24, 0x6d, 0xa0, 0xef, 0x25, 0x7c, 0xb7, 0xea, + 0xce, 0x4d, 0x5f, 0x18, 0x60, 0xce, 0x87, 0x22, + 0x66, 0x2f, 0xd5, 0xdd, 0xdd, 0x02, 0x21, 0x75, + 0x82, 0xa0, 0x1f, 0x58, 0xc6, 0xd3, 0x62, 0xf7, + 0x32, 0xd8, 0xaf, 0x1e, 0x07, 0x77, 0x51, 0x96, + 0xd5, 0x6b, 0x1e, 0x7e, 0x80, 0x02, 0xe8, 0x67, + 0xea, 0x17, 0x0b, 0x10, 0xd2, 0x3f, 0x28, 0x25, + 0x4f, 0x05, 0x77, 0x02, 0x14, 0x69, 0xf0, 0x2c, + 0xbe, 0x0c, 0xf1, 0x74, 0x30, 0xd1, 0xb9, 0x9b, + 0xfc, 0x8c, 0xbb, 0x04, 0x16, 0xd9, 0xba, 0xc3, + 0xbc, 0x91, 0x8a, 0xc4, 0x30, 0xa4, 0xb0, 0x12, + 0x4c, 0x21, 0x87, 0xcb, 0xc9, 0x1d, 0x16, 0x96, + 0x07, 0x6f, 0x23, 0x54, 0xb9, 0x6f, 0x79, 0xe5, + 0x64, 0xc0, 0x64, 0xda, 0xb1, 0xae, 0xdd, 0x60, + 0x6c, 0x1a, 0x9d, 0xd3, 0x04, 0x8e, 0x45, 0xb0, + 0x92, 0x61, 0xd0, 0x48, 0x81, 0xed, 0x5e, 0x1d, + 0xa0, 0xc9, 0xa4, 0x33, 0xc7, 0x13, 0x51, 0x5d, + 0x7f, 0x83, 0x73, 0xb6, 0x70, 0x18, 0x65, 0x3e, + 0x2f, 0x0e, 0x7a, 0x12, 0x39, 0x98, 0xab, 0xd8, + 0x7e, 0x6f, 0xa3, 0xd1, 0xba, 0x56, 0xad, 0xbd, + 0xf0, 0x03, 0x01, 0x1c, 0x85, 0x35, 0x9f, 0xeb, + 0x19, 0x63, 0xa1, 0xaf, 0xfe, 0x2d, 0x35, 0x50, + 0x39, 0xa0, 0x65, 0x7c, 0x95, 0x7e, 0x6b, 0xfe, + 0xc1, 0xac, 0x07, 0x7c, 0x98, 0x4f, 0xbe, 0x57, + 0xa7, 0x22, 0xec, 0xe2, 0x7e, 0x29, 0x09, 0x53, + 0xe8, 0xbf, 0xb4, 0x7e, 0x3f, 0x8f, 0xfc, 0x14, + 0xce, 0x54, 0xf9, 0x18, 0x58, 0xb5, 0xff, 0x44, + 0x05, 0x9d, 0xce, 0x1b, 0xb6, 0x82, 0x23, 0xc8, + 0x2e, 0xbc, 0x69, 0xbb, 0x4a, 0x29, 0x0f, 0x65, + 0x94, 0xf0, 0x63, 0x06, 0x0e, 0xef, 0x8c, 0xbd, + 0xff, 0xfd, 0xb0, 0x21, 0x6e, 0x57, 0x05, 0x75, + 0xda, 0xd5, 0xc4, 0xeb, 0x8d, 0x32, 0xf7, 0x50, + 0xd3, 0x6f, 0x22, 0xed, 0x5f, 0x8e, 0xa2, 0x5b, + 0x80, 0x8c, 0xc8, 0x78, 0x40, 0x24, 0x4b, 0x89, + 0x30, 0xce, 0x7a, 0x97, 0x0e, 0xc4, 0xaf, 0xef, + 0x9b, 0xb4, 0xcd, 0x66, 0x74, 0x14, 0x04, 0x2b, + 0xf7, 0xce, 0x0b, 0x1c, 0x6e, 0xc2, 0x78, 0x8c, + 0xca, 0xc5, 0xd0, 0x1c, 0x95, 0x4a, 0x91, 0x2d, + 0xa7, 0x20, 0xeb, 0x86, 0x52, 0xb7, 0x67, 0xd8, + 0x0c, 0xd6, 0x04, 0x14, 0xde, 0x51, 0x74, 0x75, + 0xe7, 0x11, 0xb4, 0x87, 0xa3, 0x3d, 0x2d, 0xad, + 0x4f, 0xef, 0xa0, 0x0f, 0x70, 0x00, 0x6d, 0x13, + 0x19, 0x1d, 0x41, 0x50, 0xe9, 0xd8, 0xf0, 0x32, + 0x71, 0xbc, 0xd3, 0x11, 0xf2, 0xac, 0xbe, 0xaf, + 0x75, 0x46, 0x65, 0x4e, 0x07, 0x34, 0x37, 0xa3, + 0x89, 0xfe, 0x75, 0xd4, 0x70, 0x4c, 0xc6, 0x3f, + 0x69, 0x24, 0x0e, 0x38, 0x67, 0x43, 0x8c, 0xde, + 0x06, 0xb5, 0xb8, 0xe7, 0xc4, 0xf0, 0x41, 0x8f, + 0xf0, 0xbd, 0x2f, 0x0b, 0xb9, 0x18, 0xf8, 0xde, + 0x64, 0xb1, 0xdb, 0xee, 0x00, 0x50, 0x77, 0xe1, + 0xc7, 0xff, 0xa6, 0xfa, 0xdd, 0x70, 0xf4, 0xe3, + 0x93, 0xe9, 0x77, 0x35, 0x3d, 0x4b, 0x2f, 0x2b, + 0x6d, 0x55, 0xf0, 0xfc, 0x88, 0x54, 0x4e, 0x89, + 0xc1, 0x8a, 0x23, 0x31, 0x2d, 0x14, 0x2a, 0xb8, + 0x1b, 0x15, 0xdd, 0x9e, 0x6e, 0x7b, 0xda, 0x05, + 0x91, 0x7d, 0x62, 0x64, 0x96, 0x72, 0xde, 0xfc, + 0xc1, 0xec, 0xf0, 0x23, 0x51, 0x6f, 0xdb, 0x5b, + 0x1d, 0x08, 0x57, 0xce, 0x09, 0xb8, 0xf6, 0xcd, + 0x8d, 0x95, 0xf2, 0x20, 0xbf, 0x0f, 0x20, 0x57, + 0x98, 0x81, 0x84, 0x4f, 0x15, 0x5c, 0x76, 0xe7, + 0x3e, 0x0a, 0x3a, 0x6c, 0xc4, 0x8a, 0xbe, 0x78, + 0x74, 0x77, 0xc3, 0x09, 0x4b, 0x5d, 0x48, 0xe4, + 0xc8, 0xcb, 0x0b, 0xea, 0x17, 0x28, 0xcf, 0xcf, + 0x31, 0x32, 0x44, 0xa4, 0xe5, 0x0e, 0x1a, 0x98, + 0x94, 0xc4, 0xf0, 0xff, 0xae, 0x3e, 0x44, 0xe8, + 0xa5, 0xb3, 0xb5, 0x37, 0x2f, 0xe8, 0xaf, 0x6f, + 0x28, 0xc1, 0x37, 0x5f, 0x31, 0xd2, 0xb9, 0x33, + 0xb1, 0xb2, 0x52, 0x94, 0x75, 0x2c, 0x29, 0x59, + 0x06, 0xc2, 0x25, 0xe8, 0x71, 0x65, 0x4e, 0xed, + 0xc0, 0x9c, 0xb1, 0xbb, 0x25, 0xdc, 0x6c, 0xe7, + 0x4b, 0xa5, 0x7a, 0x54, 0x7a, 0x60, 0xff, 0x7a, + 0xe0, 0x50, 0x40, 0x96, 0x35, 0x63, 0xe4, 0x0b, + 0x76, 0xbd, 0xa4, 0x65, 0x00, 0x1b, 0x57, 0x88, + 0xae, 0xed, 0x39, 0x88, 0x42, 0x11, 0x3c, 0xed, + 0x85, 0x67, 0x7d, 0xb9, 0x68, 0x82, 0xe9, 0x43, + 0x3c, 0x47, 0x53, 0xfa, 0xe8, 0xf8, 0x9f, 0x1f, + 0x9f, 0xef, 0x0f, 0xf7, 0x30, 0xd9, 0x30, 0x0e, + 0xb9, 0x9f, 0x69, 0x18, 0x2f, 0x7e, 0xf8, 0xf8, + 0xf8, 0x8c, 0x0f, 0xd4, 0x02, 0x4d, 0xea, 0xcd, + 0x0a, 0x9c, 0x6f, 0x71, 0x6d, 0x5a, 0x4c, 0x60, + 0xce, 0x20, 0x56, 0x32, 0xc6, 0xc5, 0x99, 0x1f, + 0x09, 0xe6, 0x4e, 0x18, 0x1a, 0x15, 0x13, 0xa8, + 0x7d, 0xb1, 0x6b, 0xc0, 0xb2, 0x6d, 0xf8, 0x26, + 0x66, 0xf8, 0x3d, 0x18, 0x74, 0x70, 0x66, 0x7a, + 0x34, 0x17, 0xde, 0xba, 0x47, 0xf1, 0x06, 0x18, + 0xcb, 0xaf, 0xeb, 0x4a, 0x1e, 0x8f, 0xa7, 0x77, + 0xe0, 0x3b, 0x78, 0x62, 0x66, 0xc9, 0x10, 0xea, + 0x1f, 0xb7, 0x29, 0x0a, 0x45, 0xa1, 0x1d, 0x1e, + 0x1d, 0xe2, 0x65, 0x61, 0x50, 0x9c, 0xd7, 0x05, + 0xf2, 0x0b, 0x5b, 0x12, 0x61, 0x02, 0xc8, 0xe5, + 0x63, 0x4f, 0x20, 0x0c, 0x07, 0x17, 0x33, 0x5e, + 0x03, 0x9a, 0x53, 0x0f, 0x2e, 0x55, 0xfe, 0x50, + 0x43, 0x7d, 0xd0, 0xb6, 0x7e, 0x5a, 0xda, 0xae, + 0x58, 0xef, 0x15, 0xa9, 0x83, 0xd9, 0x46, 0xb1, + 0x42, 0xaa, 0xf5, 0x02, 0x6c, 0xce, 0x92, 0x06, + 0x1b, 0xdb, 0x66, 0x45, 0x91, 0x79, 0xc2, 0x2d, + 0xe6, 0x53, 0xd3, 0x14, 0xfd, 0xbb, 0x44, 0x63, + 0xc6, 0xd7, 0x3d, 0x7a, 0x0c, 0x75, 0x78, 0x9d, + 0x5c, 0xa6, 0x39, 0xb3, 0xe5, 0x63, 0xca, 0x8b, + 0xfe, 0xd3, 0xef, 0x60, 0x83, 0xf6, 0x8e, 0x70, + 0xb6, 0x67, 0xc7, 0x77, 0xed, 0x23, 0xef, 0x4c, + 0xf0, 0xed, 0x2d, 0x07, 0x59, 0x6f, 0xc1, 0x01, + 0x34, 0x37, 0x08, 0xab, 0xd9, 0x1f, 0x09, 0xb1, + 0xce, 0x5b, 0x17, 0xff, 0x74, 0xf8, 0x9c, 0xd5, + 0x2c, 0x56, 0x39, 0x79, 0x0f, 0x69, 0x44, 0x75, + 0x58, 0x27, 0x01, 0xc4, 0xbf, 0xa7, 0xa1, 0x1d, + 0x90, 0x17, 0x77, 0x86, 0x5a, 0x3f, 0xd9, 0xd1, + 0x0e, 0xa0, 0x10, 0xf8, 0xec, 0x1e, 0xa5, 0x7f, + 0x5e, 0x36, 0xd1, 0xe3, 0x04, 0x2c, 0x70, 0xf7, + 0x8e, 0xc0, 0x98, 0x2f, 0x6c, 0x94, 0x2b, 0x41, + 0xb7, 0x60, 0x00, 0xb7, 0x2e, 0xb8, 0x02, 0x8d, + 0xb8, 0xb0, 0xd3, 0x86, 0xba, 0x1d, 0xd7, 0x90, + 0xd6, 0xb6, 0xe1, 0xfc, 0xd7, 0xd8, 0x28, 0x06, + 0x63, 0x9b, 0xce, 0x61, 0x24, 0x79, 0xc0, 0x70, + 0x52, 0xd0, 0xb6, 0xd4, 0x28, 0x95, 0x24, 0x87, + 0x03, 0x1f, 0xb7, 0x9a, 0xda, 0xa3, 0xfb, 0x52, + 0x5b, 0x68, 0xe7, 0x4c, 0x8c, 0x24, 0xe1, 0x42, + 0xf7, 0xd5, 0xfd, 0xad, 0x06, 0x32, 0x9f, 0xba, + 0xc1, 0xfc, 0xdd, 0xc6, 0xfc, 0xfc, 0xb3, 0x38, + 0x74, 0x56, 0x58, 0x40, 0x02, 0x37, 0x52, 0x2c, + 0x55, 0xcc, 0xb3, 0x9e, 0x7a, 0xe9, 0xd4, 0x38, + 0x41, 0x5e, 0x0c, 0x35, 0xe2, 0x11, 0xd1, 0x13, + 0xf8, 0xb7, 0x8d, 0x72, 0x6b, 0x22, 0x2a, 0xb0, + 0xdb, 0x08, 0xba, 0x35, 0xb9, 0x3f, 0xc8, 0xd3, + 0x24, 0x90, 0xec, 0x58, 0xd2, 0x09, 0xc7, 0x2d, + 0xed, 0x38, 0x80, 0x36, 0x72, 0x43, 0x27, 0x49, + 0x4a, 0x80, 0x8a, 0xa2, 0xe8, 0xd3, 0xda, 0x30, + 0x7d, 0xb6, 0x82, 0x37, 0x86, 0x92, 0x86, 0x3e, + 0x08, 0xb2, 0x28, 0x5a, 0x55, 0x44, 0x24, 0x7d, + 0x40, 0x48, 0x8a, 0xb6, 0x89, 0x58, 0x08, 0xa0, + 0xd6, 0x6d, 0x3a, 0x17, 0xbf, 0xf6, 0x54, 0xa2, + 0xf5, 0xd3, 0x8c, 0x0f, 0x78, 0x12, 0x57, 0x8b, + 0xd5, 0xc2, 0xfd, 0x58, 0x5b, 0x7f, 0x38, 0xe3, + 0xcc, 0xb7, 0x7c, 0x48, 0xb3, 0x20, 0xe8, 0x81, + 0x14, 0x32, 0x45, 0x05, 0xe0, 0xdb, 0x9f, 0x75, + 0x85, 0xb4, 0x6a, 0xfc, 0x95, 0xe3, 0x54, 0x22, + 0x12, 0xee, 0x30, 0xfe, 0xd8, 0x30, 0xef, 0x34, + 0x50, 0xab, 0x46, 0x30, 0x98, 0x2f, 0xb7, 0xc0, + 0x15, 0xa2, 0x83, 0xb6, 0xf2, 0x06, 0x21, 0xa2, + 0xc3, 0x26, 0x37, 0x14, 0xd1, 0x4d, 0xb5, 0x10, + 0x52, 0x76, 0x4d, 0x6a, 0xee, 0xb5, 0x2b, 0x15, + 0xb7, 0xf9, 0x51, 0xe8, 0x2a, 0xaf, 0xc7, 0xfa, + 0x77, 0xaf, 0xb0, 0x05, 0x4d, 0xd1, 0x68, 0x8e, + 0x74, 0x05, 0x9f, 0x9d, 0x93, 0xa5, 0x3e, 0x7f, + 0x4e, 0x5f, 0x9d, 0xcb, 0x09, 0xc7, 0x83, 0xe3, + 0x02, 0x9d, 0x27, 0x1f, 0xef, 0x85, 0x05, 0x8d, + 0xec, 0x55, 0x88, 0x0f, 0x0d, 0x7c, 0x4c, 0xe8, + 0xa1, 0x75, 0xa0, 0xd8, 0x06, 0x47, 0x14, 0xef, + 0xaa, 0x61, 0xcf, 0x26, 0x15, 0xad, 0xd8, 0xa3, + 0xaa, 0x75, 0xf2, 0x78, 0x4a, 0x5a, 0x61, 0xdf, + 0x8b, 0xc7, 0x04, 0xbc, 0xb2, 0x32, 0xd2, 0x7e, + 0x42, 0xee, 0xb4, 0x2f, 0x51, 0xff, 0x7b, 0x2e, + 0xd3, 0x02, 0xe8, 0xdc, 0x5d, 0x0d, 0x50, 0xdc, + 0xae, 0xb7, 0x46, 0xf9, 0xa8, 0xe6, 0xd0, 0x16, + 0xcc, 0xe6, 0x2c, 0x81, 0xc7, 0xad, 0xe9, 0xf0, + 0x05, 0x72, 0x6d, 0x3d, 0x0a, 0x7a, 0xa9, 0x02, + 0xac, 0x82, 0x93, 0x6e, 0xb6, 0x1c, 0x28, 0xfc, + 0x44, 0x12, 0xfb, 0x73, 0x77, 0xd4, 0x13, 0x39, + 0x29, 0x88, 0x8a, 0xf3, 0x5c, 0xa6, 0x36, 0xa0, + 0x2a, 0xed, 0x7e, 0xb1, 0x1d, 0xd6, 0x4c, 0x6b, + 0x41, 0x01, 0x18, 0x5d, 0x5d, 0x07, 0x97, 0xa6, + 0x4b, 0xef, 0x31, 0x18, 0xea, 0xac, 0xb1, 0x84, + 0x21, 0xed, 0xda, 0x86, + }, + .rlen = 4100, + }, +}; + +static struct cipher_testvec aes_ctr_dec_tv_template[] = { + { /* From RFC 3686 */ + .key = { 0xae, 0x68, 0x52, 0xf8, 0x12, 0x10, 0x67, 0xcc, + 0x4b, 0xf7, 0xa5, 0x76, 0x55, 0x77, 0xf3, 0x9e, + 0x00, 0x00, 0x00, 0x30 }, + .klen = 20, + .iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .input = { 0xe4, 0x09, 0x5d, 0x4f, 0xb7, 0xa7, 0xb3, 0x79, + 0x2d, 0x61, 0x75, 0xa3, 0x26, 0x13, 0x11, 0xb8 }, + .ilen = 16, + .result = { "Single block msg" }, + .rlen = 16, + }, { + .key = { 0x7e, 0x24, 0x06, 0x78, 0x17, 0xfa, 0xe0, 0xd7, + 0x43, 0xd6, 0xce, 0x1f, 0x32, 0x53, 0x91, 0x63, + 0x00, 0x6c, 0xb6, 0xdb }, + .klen = 20, + .iv = { 0xc0, 0x54, 0x3b, 0x59, 0xda, 0x48, 0xd9, 0x0b }, + .input = { 0x51, 0x04, 0xa1, 0x06, 0x16, 0x8a, 0x72, 0xd9, + 0x79, 0x0d, 0x41, 0xee, 0x8e, 0xda, 0xd3, 0x88, + 0xeb, 0x2e, 0x1e, 0xfc, 0x46, 0xda, 0x57, 0xc8, + 0xfc, 0xe6, 0x30, 0xdf, 0x91, 0x41, 0xbe, 0x28 }, + .ilen = 32, + .result = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }, + .rlen = 32, + }, { + .key = { 0x16, 0xaf, 0x5b, 0x14, 0x5f, 0xc9, 0xf5, 0x79, + 0xc1, 0x75, 0xf9, 0x3e, 0x3b, 0xfb, 0x0e, 0xed, + 0x86, 0x3d, 0x06, 0xcc, 0xfd, 0xb7, 0x85, 0x15, + 0x00, 0x00, 0x00, 0x48 }, + .klen = 28, + .iv = { 0x36, 0x73, 0x3c, 0x14, 0x7d, 0x6d, 0x93, 0xcb }, + .input = { 0x4b, 0x55, 0x38, 0x4f, 0xe2, 0x59, 0xc9, 0xc8, + 0x4e, 0x79, 0x35, 0xa0, 0x03, 0xcb, 0xe9, 0x28 }, + .ilen = 16, + .result = { "Single block msg" }, + .rlen = 16, + }, { + .key = { 0x7c, 0x5c, 0xb2, 0x40, 0x1b, 0x3d, 0xc3, 0x3c, + 0x19, 0xe7, 0x34, 0x08, 0x19, 0xe0, 0xf6, 0x9c, + 0x67, 0x8c, 0x3d, 0xb8, 0xe6, 0xf6, 0xa9, 0x1a, + 0x00, 0x96, 0xb0, 0x3b }, + .klen = 28, + .iv = { 0x02, 0x0c, 0x6e, 0xad, 0xc2, 0xcb, 0x50, 0x0d }, + .input = { 0x45, 0x32, 0x43, 0xfc, 0x60, 0x9b, 0x23, 0x32, + 0x7e, 0xdf, 0xaa, 0xfa, 0x71, 0x31, 0xcd, 0x9f, + 0x84, 0x90, 0x70, 0x1c, 0x5a, 0xd4, 0xa7, 0x9c, + 0xfc, 0x1f, 0xe0, 0xff, 0x42, 0xf4, 0xfb, 0x00 }, + .ilen = 32, + .result = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }, + .rlen = 32, + }, { + .key = { 0x77, 0x6b, 0xef, 0xf2, 0x85, 0x1d, 0xb0, 0x6f, + 0x4c, 0x8a, 0x05, 0x42, 0xc8, 0x69, 0x6f, 0x6c, + 0x6a, 0x81, 0xaf, 0x1e, 0xec, 0x96, 0xb4, 0xd3, + 0x7f, 0xc1, 0xd6, 0x89, 0xe6, 0xc1, 0xc1, 0x04, + 0x00, 0x00, 0x00, 0x60 }, + .klen = 36, + .iv = { 0xdb, 0x56, 0x72, 0xc9, 0x7a, 0xa8, 0xf0, 0xb2 }, + .input = { 0x14, 0x5a, 0xd0, 0x1d, 0xbf, 0x82, 0x4e, 0xc7, + 0x56, 0x08, 0x63, 0xdc, 0x71, 0xe3, 0xe0, 0xc0 }, + .ilen = 16, + .result = { "Single block msg" }, + .rlen = 16, + }, { + .key = { 0xf6, 0xd6, 0x6d, 0x6b, 0xd5, 0x2d, 0x59, 0xbb, + 0x07, 0x96, 0x36, 0x58, 0x79, 0xef, 0xf8, 0x86, + 0xc6, 0x6d, 0xd5, 0x1a, 0x5b, 0x6a, 0x99, 0x74, + 0x4b, 0x50, 0x59, 0x0c, 0x87, 0xa2, 0x38, 0x84, + 0x00, 0xfa, 0xac, 0x24 }, + .klen = 36, + .iv = { 0xc1, 0x58, 0x5e, 0xf1, 0x5a, 0x43, 0xd8, 0x75 }, + .input = { 0xf0, 0x5e, 0x23, 0x1b, 0x38, 0x94, 0x61, 0x2c, + 0x49, 0xee, 0x00, 0x0b, 0x80, 0x4e, 0xb2, 0xa9, + 0xb8, 0x30, 0x6b, 0x50, 0x8f, 0x83, 0x9d, 0x6a, + 0x55, 0x30, 0x83, 0x1d, 0x93, 0x44, 0xaf, 0x1c }, + .ilen = 32, + .result = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }, + .rlen = 32, + }, +}; + +static struct aead_testvec aes_gcm_enc_tv_template[] = { + { /* From McGrew & Viega - http://citeseer.ist.psu.edu/656989.html */ + .klen = 16, + .result = { 0x58, 0xe2, 0xfc, 0xce, 0xfa, 0x7e, 0x30, 0x61, + 0x36, 0x7f, 0x1d, 0x57, 0xa4, 0xe7, 0x45, 0x5a }, + .rlen = 16, + }, { + .klen = 16, + .ilen = 16, + .result = { 0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92, + 0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2, 0xfe, 0x78, + 0xab, 0x6e, 0x47, 0xd4, 0x2c, 0xec, 0x13, 0xbd, + 0xf5, 0x3a, 0x67, 0xb2, 0x12, 0x57, 0xbd, 0xdf }, + .rlen = 32, + }, { + .key = { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 }, + .klen = 16, + .iv = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }, + .input = { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 }, + .ilen = 64, + .result = { 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, + 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c, + 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, + 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, + 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, + 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, + 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, + 0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85, + 0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6, + 0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6, 0xfa, 0xb4 }, + .rlen = 80, + }, { + .key = { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 }, + .klen = 16, + .iv = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }, + .input = { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39 }, + .ilen = 60, + .assoc = { 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xab, 0xad, 0xda, 0xd2 }, + .alen = 20, + .result = { 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, + 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c, + 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, + 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, + 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, + 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, + 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, + 0x3d, 0x58, 0xe0, 0x91, + 0x5b, 0xc9, 0x4f, 0xbc, 0x32, 0x21, 0xa5, 0xdb, + 0x94, 0xfa, 0xe9, 0x5a, 0xe7, 0x12, 0x1a, 0x47 }, + .rlen = 76, + }, { + .klen = 24, + .result = { 0xcd, 0x33, 0xb2, 0x8a, 0xc7, 0x73, 0xf7, 0x4b, + 0xa0, 0x0e, 0xd1, 0xf3, 0x12, 0x57, 0x24, 0x35 }, + .rlen = 16, + }, { + .klen = 24, + .ilen = 16, + .result = { 0x98, 0xe7, 0x24, 0x7c, 0x07, 0xf0, 0xfe, 0x41, + 0x1c, 0x26, 0x7e, 0x43, 0x84, 0xb0, 0xf6, 0x00, + 0x2f, 0xf5, 0x8d, 0x80, 0x03, 0x39, 0x27, 0xab, + 0x8e, 0xf4, 0xd4, 0x58, 0x75, 0x14, 0xf0, 0xfb }, + .rlen = 32, + }, { + .key = { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c }, + .klen = 24, + .iv = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }, + .input = { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 }, + .ilen = 64, + .result = { 0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41, + 0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57, + 0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84, + 0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c, + 0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25, + 0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47, + 0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9, + 0xcc, 0xda, 0x27, 0x10, 0xac, 0xad, 0xe2, 0x56, + 0x99, 0x24, 0xa7, 0xc8, 0x58, 0x73, 0x36, 0xbf, + 0xb1, 0x18, 0x02, 0x4d, 0xb8, 0x67, 0x4a, 0x14 }, + .rlen = 80, + }, { + .key = { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c }, + .klen = 24, + .iv = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }, + .input = { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39 }, + .ilen = 60, + .assoc = { 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xab, 0xad, 0xda, 0xd2 }, + .alen = 20, + .result = { 0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41, + 0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57, + 0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84, + 0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c, + 0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25, + 0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47, + 0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9, + 0xcc, 0xda, 0x27, 0x10, + 0x25, 0x19, 0x49, 0x8e, 0x80, 0xf1, 0x47, 0x8f, + 0x37, 0xba, 0x55, 0xbd, 0x6d, 0x27, 0x61, 0x8c }, + .rlen = 76, + .np = 2, + .tap = { 32, 28 }, + .anp = 2, + .atap = { 8, 12 } + }, { + .klen = 32, + .result = { 0x53, 0x0f, 0x8a, 0xfb, 0xc7, 0x45, 0x36, 0xb9, + 0xa9, 0x63, 0xb4, 0xf1, 0xc4, 0xcb, 0x73, 0x8b }, + .rlen = 16, + } +}; + +static struct aead_testvec aes_gcm_dec_tv_template[] = { + { /* From McGrew & Viega - http://citeseer.ist.psu.edu/656989.html */ + .klen = 32, + .input = { 0xce, 0xa7, 0x40, 0x3d, 0x4d, 0x60, 0x6b, 0x6e, + 0x07, 0x4e, 0xc5, 0xd3, 0xba, 0xf3, 0x9d, 0x18, + 0xd0, 0xd1, 0xc8, 0xa7, 0x99, 0x99, 0x6b, 0xf0, + 0x26, 0x5b, 0x98, 0xb5, 0xd4, 0x8a, 0xb9, 0x19 }, + .ilen = 32, + .rlen = 16, + }, { + .key = { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 }, + .klen = 32, + .iv = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }, + .input = { 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, + 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d, + 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9, + 0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa, + 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d, + 0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38, + 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a, + 0xbc, 0xc9, 0xf6, 0x62, 0x89, 0x80, 0x15, 0xad, + 0xb0, 0x94, 0xda, 0xc5, 0xd9, 0x34, 0x71, 0xbd, + 0xec, 0x1a, 0x50, 0x22, 0x70, 0xe3, 0xcc, 0x6c }, + .ilen = 80, + .result = { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 }, + .rlen = 64, + }, { + .key = { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 }, + .klen = 32, + .iv = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }, + .input = { 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, + 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d, + 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9, + 0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa, + 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d, + 0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38, + 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a, + 0xbc, 0xc9, 0xf6, 0x62, + 0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68, + 0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d, 0x55, 0x1b }, + .ilen = 76, + .assoc = { 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xab, 0xad, 0xda, 0xd2 }, + .alen = 20, + .result = { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39 }, + .rlen = 60, + .np = 2, + .tap = { 48, 28 }, + .anp = 3, + .atap = { 8, 8, 4 } + }, { + .key = { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 }, + .klen = 16, + .iv = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }, + .input = { 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, + 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c, + 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, + 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, + 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, + 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, + 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, + 0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85, + 0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6, + 0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6, 0xfa, 0xb4 }, + .ilen = 80, + .result = { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 }, + .rlen = 64, + }, { + .key = { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 }, + .klen = 16, + .iv = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }, + .input = { 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, + 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c, + 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, + 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, + 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, + 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, + 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, + 0x3d, 0x58, 0xe0, 0x91, + 0x5b, 0xc9, 0x4f, 0xbc, 0x32, 0x21, 0xa5, 0xdb, + 0x94, 0xfa, 0xe9, 0x5a, 0xe7, 0x12, 0x1a, 0x47 }, + .ilen = 76, + .assoc = { 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xab, 0xad, 0xda, 0xd2 }, + .alen = 20, + .result = { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39 }, + .rlen = 60, + }, { + .klen = 24, + .input = { 0x98, 0xe7, 0x24, 0x7c, 0x07, 0xf0, 0xfe, 0x41, + 0x1c, 0x26, 0x7e, 0x43, 0x84, 0xb0, 0xf6, 0x00, + 0x2f, 0xf5, 0x8d, 0x80, 0x03, 0x39, 0x27, 0xab, + 0x8e, 0xf4, 0xd4, 0x58, 0x75, 0x14, 0xf0, 0xfb }, + .ilen = 32, + .rlen = 16, + }, { + .key = { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c }, + .klen = 24, + .iv = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }, + .input = { 0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41, + 0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57, + 0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84, + 0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c, + 0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25, + 0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47, + 0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9, + 0xcc, 0xda, 0x27, 0x10, 0xac, 0xad, 0xe2, 0x56, + 0x99, 0x24, 0xa7, 0xc8, 0x58, 0x73, 0x36, 0xbf, + 0xb1, 0x18, 0x02, 0x4d, 0xb8, 0x67, 0x4a, 0x14 }, + .ilen = 80, + .result = { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 }, + .rlen = 64, + }, { + .key = { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c }, + .klen = 24, + .iv = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }, + .input = { 0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41, + 0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57, + 0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84, + 0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c, + 0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25, + 0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47, + 0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9, + 0xcc, 0xda, 0x27, 0x10, + 0x25, 0x19, 0x49, 0x8e, 0x80, 0xf1, 0x47, 0x8f, + 0x37, 0xba, 0x55, 0xbd, 0x6d, 0x27, 0x61, 0x8c }, + .ilen = 76, + .assoc = { 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xab, 0xad, 0xda, 0xd2 }, + .alen = 20, + .result = { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39 }, + .rlen = 60, + } +}; + +static struct aead_testvec aes_ccm_enc_tv_template[] = { + { /* From RFC 3610 */ + .key = { 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf }, + .klen = 16, + .iv = { 0x01, 0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0x00, 0x00 }, + .assoc = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }, + .alen = 8, + .input = { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e }, + .ilen = 23, + .result = { 0x58, 0x8c, 0x97, 0x9a, 0x61, 0xc6, 0x63, 0xd2, + 0xf0, 0x66, 0xd0, 0xc2, 0xc0, 0xf9, 0x89, 0x80, + 0x6d, 0x5f, 0x6b, 0x61, 0xda, 0xc3, 0x84, 0x17, + 0xe8, 0xd1, 0x2c, 0xfd, 0xf9, 0x26, 0xe0 }, + .rlen = 31, + }, { + .key = { 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf }, + .klen = 16, + .iv = { 0x01, 0x00, 0x00, 0x00, 0x07, 0x06, 0x05, 0x04, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0x00, 0x00 }, + .assoc = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b }, + .alen = 12, + .input = { 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f }, + .ilen = 20, + .result = { 0xdc, 0xf1, 0xfb, 0x7b, 0x5d, 0x9e, 0x23, 0xfb, + 0x9d, 0x4e, 0x13, 0x12, 0x53, 0x65, 0x8a, 0xd8, + 0x6e, 0xbd, 0xca, 0x3e, 0x51, 0xe8, 0x3f, 0x07, + 0x7d, 0x9c, 0x2d, 0x93 }, + .rlen = 28, + }, { + .key = { 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf }, + .klen = 16, + .iv = { 0x01, 0x00, 0x00, 0x00, 0x0b, 0x0a, 0x09, 0x08, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0x00, 0x00 }, + .assoc = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }, + .alen = 8, + .input = { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20 }, + .ilen = 25, + .result = { 0x82, 0x53, 0x1a, 0x60, 0xcc, 0x24, 0x94, 0x5a, + 0x4b, 0x82, 0x79, 0x18, 0x1a, 0xb5, 0xc8, 0x4d, + 0xf2, 0x1c, 0xe7, 0xf9, 0xb7, 0x3f, 0x42, 0xe1, + 0x97, 0xea, 0x9c, 0x07, 0xe5, 0x6b, 0x5e, 0xb1, + 0x7e, 0x5f, 0x4e }, + .rlen = 35, + }, { + .key = { 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf }, + .klen = 16, + .iv = { 0x01, 0x00, 0x00, 0x00, 0x0c, 0x0b, 0x0a, 0x09, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0x00, 0x00 }, + .assoc = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b }, + .alen = 12, + .input = { 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e }, + .ilen = 19, + .result = { 0x07, 0x34, 0x25, 0x94, 0x15, 0x77, 0x85, 0x15, + 0x2b, 0x07, 0x40, 0x98, 0x33, 0x0a, 0xbb, 0x14, + 0x1b, 0x94, 0x7b, 0x56, 0x6a, 0xa9, 0x40, 0x6b, + 0x4d, 0x99, 0x99, 0x88, 0xdd }, + .rlen = 29, + }, { + .key = { 0xd7, 0x82, 0x8d, 0x13, 0xb2, 0xb0, 0xbd, 0xc3, + 0x25, 0xa7, 0x62, 0x36, 0xdf, 0x93, 0xcc, 0x6b }, + .klen = 16, + .iv = { 0x01, 0x00, 0x33, 0x56, 0x8e, 0xf7, 0xb2, 0x63, + 0x3c, 0x96, 0x96, 0x76, 0x6c, 0xfa, 0x00, 0x00 }, + .assoc = { 0x63, 0x01, 0x8f, 0x76, 0xdc, 0x8a, 0x1b, 0xcb }, + .alen = 8, + .input = { 0x90, 0x20, 0xea, 0x6f, 0x91, 0xbd, 0xd8, 0x5a, + 0xfa, 0x00, 0x39, 0xba, 0x4b, 0xaf, 0xf9, 0xbf, + 0xb7, 0x9c, 0x70, 0x28, 0x94, 0x9c, 0xd0, 0xec }, + .ilen = 24, + .result = { 0x4c, 0xcb, 0x1e, 0x7c, 0xa9, 0x81, 0xbe, 0xfa, + 0xa0, 0x72, 0x6c, 0x55, 0xd3, 0x78, 0x06, 0x12, + 0x98, 0xc8, 0x5c, 0x92, 0x81, 0x4a, 0xbc, 0x33, + 0xc5, 0x2e, 0xe8, 0x1d, 0x7d, 0x77, 0xc0, 0x8a }, + .rlen = 32, + }, { + .key = { 0xd7, 0x82, 0x8d, 0x13, 0xb2, 0xb0, 0xbd, 0xc3, + 0x25, 0xa7, 0x62, 0x36, 0xdf, 0x93, 0xcc, 0x6b }, + .klen = 16, + .iv = { 0x01, 0x00, 0xd5, 0x60, 0x91, 0x2d, 0x3f, 0x70, + 0x3c, 0x96, 0x96, 0x76, 0x6c, 0xfa, 0x00, 0x00 }, + .assoc = { 0xcd, 0x90, 0x44, 0xd2, 0xb7, 0x1f, 0xdb, 0x81, + 0x20, 0xea, 0x60, 0xc0 }, + .alen = 12, + .input = { 0x64, 0x35, 0xac, 0xba, 0xfb, 0x11, 0xa8, 0x2e, + 0x2f, 0x07, 0x1d, 0x7c, 0xa4, 0xa5, 0xeb, 0xd9, + 0x3a, 0x80, 0x3b, 0xa8, 0x7f }, + .ilen = 21, + .result = { 0x00, 0x97, 0x69, 0xec, 0xab, 0xdf, 0x48, 0x62, + 0x55, 0x94, 0xc5, 0x92, 0x51, 0xe6, 0x03, 0x57, + 0x22, 0x67, 0x5e, 0x04, 0xc8, 0x47, 0x09, 0x9e, + 0x5a, 0xe0, 0x70, 0x45, 0x51 }, + .rlen = 29, + }, { + .key = { 0xd7, 0x82, 0x8d, 0x13, 0xb2, 0xb0, 0xbd, 0xc3, + 0x25, 0xa7, 0x62, 0x36, 0xdf, 0x93, 0xcc, 0x6b }, + .klen = 16, + .iv = { 0x01, 0x00, 0x42, 0xff, 0xf8, 0xf1, 0x95, 0x1c, + 0x3c, 0x96, 0x96, 0x76, 0x6c, 0xfa, 0x00, 0x00 }, + .assoc = { 0xd8, 0x5b, 0xc7, 0xe6, 0x9f, 0x94, 0x4f, 0xb8 }, + .alen = 8, + .input = { 0x8a, 0x19, 0xb9, 0x50, 0xbc, 0xf7, 0x1a, 0x01, + 0x8e, 0x5e, 0x67, 0x01, 0xc9, 0x17, 0x87, 0x65, + 0x98, 0x09, 0xd6, 0x7d, 0xbe, 0xdd, 0x18 }, + .ilen = 23, + .result = { 0xbc, 0x21, 0x8d, 0xaa, 0x94, 0x74, 0x27, 0xb6, + 0xdb, 0x38, 0x6a, 0x99, 0xac, 0x1a, 0xef, 0x23, + 0xad, 0xe0, 0xb5, 0x29, 0x39, 0xcb, 0x6a, 0x63, + 0x7c, 0xf9, 0xbe, 0xc2, 0x40, 0x88, 0x97, 0xc6, + 0xba }, + .rlen = 33, + }, +}; + +static struct aead_testvec aes_ccm_dec_tv_template[] = { + { /* From RFC 3610 */ + .key = { 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf }, + .klen = 16, + .iv = { 0x01, 0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0x00, 0x00 }, + .assoc = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }, + .alen = 8, + .input = { 0x58, 0x8c, 0x97, 0x9a, 0x61, 0xc6, 0x63, 0xd2, + 0xf0, 0x66, 0xd0, 0xc2, 0xc0, 0xf9, 0x89, 0x80, + 0x6d, 0x5f, 0x6b, 0x61, 0xda, 0xc3, 0x84, 0x17, + 0xe8, 0xd1, 0x2c, 0xfd, 0xf9, 0x26, 0xe0 }, + .ilen = 31, + .result = { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e }, + .rlen = 23, + }, { + .key = { 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf }, + .klen = 16, + .iv = { 0x01, 0x00, 0x00, 0x00, 0x07, 0x06, 0x05, 0x04, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0x00, 0x00 }, + .assoc = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b }, + .alen = 12, + .input = { 0xdc, 0xf1, 0xfb, 0x7b, 0x5d, 0x9e, 0x23, 0xfb, + 0x9d, 0x4e, 0x13, 0x12, 0x53, 0x65, 0x8a, 0xd8, + 0x6e, 0xbd, 0xca, 0x3e, 0x51, 0xe8, 0x3f, 0x07, + 0x7d, 0x9c, 0x2d, 0x93 }, + .ilen = 28, + .result = { 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f }, + .rlen = 20, + }, { + .key = { 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf }, + .klen = 16, + .iv = { 0x01, 0x00, 0x00, 0x00, 0x0b, 0x0a, 0x09, 0x08, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0x00, 0x00 }, + .assoc = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }, + .alen = 8, + .input = { 0x82, 0x53, 0x1a, 0x60, 0xcc, 0x24, 0x94, 0x5a, + 0x4b, 0x82, 0x79, 0x18, 0x1a, 0xb5, 0xc8, 0x4d, + 0xf2, 0x1c, 0xe7, 0xf9, 0xb7, 0x3f, 0x42, 0xe1, + 0x97, 0xea, 0x9c, 0x07, 0xe5, 0x6b, 0x5e, 0xb1, + 0x7e, 0x5f, 0x4e }, + .ilen = 35, + .result = { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20 }, + .rlen = 25, + }, { + .key = { 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf }, + .klen = 16, + .iv = { 0x01, 0x00, 0x00, 0x00, 0x0c, 0x0b, 0x0a, 0x09, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0x00, 0x00 }, + .assoc = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b }, + .alen = 12, + .input = { 0x07, 0x34, 0x25, 0x94, 0x15, 0x77, 0x85, 0x15, + 0x2b, 0x07, 0x40, 0x98, 0x33, 0x0a, 0xbb, 0x14, + 0x1b, 0x94, 0x7b, 0x56, 0x6a, 0xa9, 0x40, 0x6b, + 0x4d, 0x99, 0x99, 0x88, 0xdd }, + .ilen = 29, + .result = { 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e }, + .rlen = 19, + }, { + .key = { 0xd7, 0x82, 0x8d, 0x13, 0xb2, 0xb0, 0xbd, 0xc3, + 0x25, 0xa7, 0x62, 0x36, 0xdf, 0x93, 0xcc, 0x6b }, + .klen = 16, + .iv = { 0x01, 0x00, 0x33, 0x56, 0x8e, 0xf7, 0xb2, 0x63, + 0x3c, 0x96, 0x96, 0x76, 0x6c, 0xfa, 0x00, 0x00 }, + .assoc = { 0x63, 0x01, 0x8f, 0x76, 0xdc, 0x8a, 0x1b, 0xcb }, + .alen = 8, + .input = { 0x4c, 0xcb, 0x1e, 0x7c, 0xa9, 0x81, 0xbe, 0xfa, + 0xa0, 0x72, 0x6c, 0x55, 0xd3, 0x78, 0x06, 0x12, + 0x98, 0xc8, 0x5c, 0x92, 0x81, 0x4a, 0xbc, 0x33, + 0xc5, 0x2e, 0xe8, 0x1d, 0x7d, 0x77, 0xc0, 0x8a }, + .ilen = 32, + .result = { 0x90, 0x20, 0xea, 0x6f, 0x91, 0xbd, 0xd8, 0x5a, + 0xfa, 0x00, 0x39, 0xba, 0x4b, 0xaf, 0xf9, 0xbf, + 0xb7, 0x9c, 0x70, 0x28, 0x94, 0x9c, 0xd0, 0xec }, + .rlen = 24, + }, { + .key = { 0xd7, 0x82, 0x8d, 0x13, 0xb2, 0xb0, 0xbd, 0xc3, + 0x25, 0xa7, 0x62, 0x36, 0xdf, 0x93, 0xcc, 0x6b }, + .klen = 16, + .iv = { 0x01, 0x00, 0xd5, 0x60, 0x91, 0x2d, 0x3f, 0x70, + 0x3c, 0x96, 0x96, 0x76, 0x6c, 0xfa, 0x00, 0x00 }, + .assoc = { 0xcd, 0x90, 0x44, 0xd2, 0xb7, 0x1f, 0xdb, 0x81, + 0x20, 0xea, 0x60, 0xc0 }, + .alen = 12, + .input = { 0x00, 0x97, 0x69, 0xec, 0xab, 0xdf, 0x48, 0x62, + 0x55, 0x94, 0xc5, 0x92, 0x51, 0xe6, 0x03, 0x57, + 0x22, 0x67, 0x5e, 0x04, 0xc8, 0x47, 0x09, 0x9e, + 0x5a, 0xe0, 0x70, 0x45, 0x51 }, + .ilen = 29, + .result = { 0x64, 0x35, 0xac, 0xba, 0xfb, 0x11, 0xa8, 0x2e, + 0x2f, 0x07, 0x1d, 0x7c, 0xa4, 0xa5, 0xeb, 0xd9, + 0x3a, 0x80, 0x3b, 0xa8, 0x7f }, + .rlen = 21, + }, { + .key = { 0xd7, 0x82, 0x8d, 0x13, 0xb2, 0xb0, 0xbd, 0xc3, + 0x25, 0xa7, 0x62, 0x36, 0xdf, 0x93, 0xcc, 0x6b }, + .klen = 16, + .iv = { 0x01, 0x00, 0x42, 0xff, 0xf8, 0xf1, 0x95, 0x1c, + 0x3c, 0x96, 0x96, 0x76, 0x6c, 0xfa, 0x00, 0x00 }, + .assoc = { 0xd8, 0x5b, 0xc7, 0xe6, 0x9f, 0x94, 0x4f, 0xb8 }, + .alen = 8, + .input = { 0xbc, 0x21, 0x8d, 0xaa, 0x94, 0x74, 0x27, 0xb6, + 0xdb, 0x38, 0x6a, 0x99, 0xac, 0x1a, 0xef, 0x23, + 0xad, 0xe0, 0xb5, 0x29, 0x39, 0xcb, 0x6a, 0x63, + 0x7c, 0xf9, 0xbe, 0xc2, 0x40, 0x88, 0x97, 0xc6, + 0xba }, + .ilen = 33, + .result = { 0x8a, 0x19, 0xb9, 0x50, 0xbc, 0xf7, 0x1a, 0x01, + 0x8e, 0x5e, 0x67, 0x01, 0xc9, 0x17, 0x87, 0x65, + 0x98, 0x09, 0xd6, 0x7d, 0xbe, 0xdd, 0x18 }, + .rlen = 23, + }, +}; + /* Cast5 test vectors from RFC 2144 */ #define CAST5_ENC_TEST_VECTORS 3 #define CAST5_DEC_TEST_VECTORS 3 @@ -4317,6 +6425,1211 @@ static struct cipher_testvec seed_dec_tv_template[] = { } }; +#define SALSA20_STREAM_ENC_TEST_VECTORS 5 +static struct cipher_testvec salsa20_stream_enc_tv_template[] = { + /* + * Testvectors from verified.test-vectors submitted to ECRYPT. + * They are truncated to size 39, 64, 111, 129 to test a variety + * of input length. + */ + { /* Set 3, vector 0 */ + .key = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F + }, + .klen = 16, + .iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .input = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .ilen = 39, + .result = { + 0x2D, 0xD5, 0xC3, 0xF7, 0xBA, 0x2B, 0x20, 0xF7, + 0x68, 0x02, 0x41, 0x0C, 0x68, 0x86, 0x88, 0x89, + 0x5A, 0xD8, 0xC1, 0xBD, 0x4E, 0xA6, 0xC9, 0xB1, + 0x40, 0xFB, 0x9B, 0x90, 0xE2, 0x10, 0x49, 0xBF, + 0x58, 0x3F, 0x52, 0x79, 0x70, 0xEB, 0xC1, + }, + .rlen = 39, + }, { /* Set 5, vector 0 */ + .key = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + .klen = 16, + .iv = { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .input = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .ilen = 64, + .result = { + 0xB6, 0x6C, 0x1E, 0x44, 0x46, 0xDD, 0x95, 0x57, + 0xE5, 0x78, 0xE2, 0x23, 0xB0, 0xB7, 0x68, 0x01, + 0x7B, 0x23, 0xB2, 0x67, 0xBB, 0x02, 0x34, 0xAE, + 0x46, 0x26, 0xBF, 0x44, 0x3F, 0x21, 0x97, 0x76, + 0x43, 0x6F, 0xB1, 0x9F, 0xD0, 0xE8, 0x86, 0x6F, + 0xCD, 0x0D, 0xE9, 0xA9, 0x53, 0x8F, 0x4A, 0x09, + 0xCA, 0x9A, 0xC0, 0x73, 0x2E, 0x30, 0xBC, 0xF9, + 0x8E, 0x4F, 0x13, 0xE4, 0xB9, 0xE2, 0x01, 0xD9, + }, + .rlen = 64, + }, { /* Set 3, vector 27 */ + .key = { + 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, + 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, + 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, + 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A + }, + .klen = 32, + .iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .input = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .ilen = 111, + .result = { + 0xAE, 0x39, 0x50, 0x8E, 0xAC, 0x9A, 0xEC, 0xE7, + 0xBF, 0x97, 0xBB, 0x20, 0xB9, 0xDE, 0xE4, 0x1F, + 0x87, 0xD9, 0x47, 0xF8, 0x28, 0x91, 0x35, 0x98, + 0xDB, 0x72, 0xCC, 0x23, 0x29, 0x48, 0x56, 0x5E, + 0x83, 0x7E, 0x0B, 0xF3, 0x7D, 0x5D, 0x38, 0x7B, + 0x2D, 0x71, 0x02, 0xB4, 0x3B, 0xB5, 0xD8, 0x23, + 0xB0, 0x4A, 0xDF, 0x3C, 0xEC, 0xB6, 0xD9, 0x3B, + 0x9B, 0xA7, 0x52, 0xBE, 0xC5, 0xD4, 0x50, 0x59, + + 0x15, 0x14, 0xB4, 0x0E, 0x40, 0xE6, 0x53, 0xD1, + 0x83, 0x9C, 0x5B, 0xA0, 0x92, 0x29, 0x6B, 0x5E, + 0x96, 0x5B, 0x1E, 0x2F, 0xD3, 0xAC, 0xC1, 0x92, + 0xB1, 0x41, 0x3F, 0x19, 0x2F, 0xC4, 0x3B, 0xC6, + 0x95, 0x46, 0x45, 0x54, 0xE9, 0x75, 0x03, 0x08, + 0x44, 0xAF, 0xE5, 0x8A, 0x81, 0x12, 0x09, + }, + .rlen = 111, + + }, { /* Set 5, vector 27 */ + .key = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + .klen = 32, + .iv = { 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00 }, + .input = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, + }, + .ilen = 129, + .result = { + 0xD2, 0xDB, 0x1A, 0x5C, 0xF1, 0xC1, 0xAC, 0xDB, + 0xE8, 0x1A, 0x7A, 0x43, 0x40, 0xEF, 0x53, 0x43, + 0x5E, 0x7F, 0x4B, 0x1A, 0x50, 0x52, 0x3F, 0x8D, + 0x28, 0x3D, 0xCF, 0x85, 0x1D, 0x69, 0x6E, 0x60, + 0xF2, 0xDE, 0x74, 0x56, 0x18, 0x1B, 0x84, 0x10, + 0xD4, 0x62, 0xBA, 0x60, 0x50, 0xF0, 0x61, 0xF2, + 0x1C, 0x78, 0x7F, 0xC1, 0x24, 0x34, 0xAF, 0x58, + 0xBF, 0x2C, 0x59, 0xCA, 0x90, 0x77, 0xF3, 0xB0, + + 0x5B, 0x4A, 0xDF, 0x89, 0xCE, 0x2C, 0x2F, 0xFC, + 0x67, 0xF0, 0xE3, 0x45, 0xE8, 0xB3, 0xB3, 0x75, + 0xA0, 0x95, 0x71, 0xA1, 0x29, 0x39, 0x94, 0xCA, + 0x45, 0x2F, 0xBD, 0xCB, 0x10, 0xB6, 0xBE, 0x9F, + 0x8E, 0xF9, 0xB2, 0x01, 0x0A, 0x5A, 0x0A, 0xB7, + 0x6B, 0x9D, 0x70, 0x8E, 0x4B, 0xD6, 0x2F, 0xCD, + 0x2E, 0x40, 0x48, 0x75, 0xE9, 0xE2, 0x21, 0x45, + 0x0B, 0xC9, 0xB6, 0xB5, 0x66, 0xBC, 0x9A, 0x59, + + 0x5A, + }, + .rlen = 129, + }, { /* large test vector generated using Crypto++ */ + .key = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + }, + .klen = 32, + .iv = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .input = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, + 0x00, 0x03, 0x06, 0x09, 0x0c, 0x0f, 0x12, 0x15, + 0x18, 0x1b, 0x1e, 0x21, 0x24, 0x27, 0x2a, 0x2d, + 0x30, 0x33, 0x36, 0x39, 0x3c, 0x3f, 0x42, 0x45, + 0x48, 0x4b, 0x4e, 0x51, 0x54, 0x57, 0x5a, 0x5d, + 0x60, 0x63, 0x66, 0x69, 0x6c, 0x6f, 0x72, 0x75, + 0x78, 0x7b, 0x7e, 0x81, 0x84, 0x87, 0x8a, 0x8d, + 0x90, 0x93, 0x96, 0x99, 0x9c, 0x9f, 0xa2, 0xa5, + 0xa8, 0xab, 0xae, 0xb1, 0xb4, 0xb7, 0xba, 0xbd, + 0xc0, 0xc3, 0xc6, 0xc9, 0xcc, 0xcf, 0xd2, 0xd5, + 0xd8, 0xdb, 0xde, 0xe1, 0xe4, 0xe7, 0xea, 0xed, + 0xf0, 0xf3, 0xf6, 0xf9, 0xfc, 0xff, 0x02, 0x05, + 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17, 0x1a, 0x1d, + 0x20, 0x23, 0x26, 0x29, 0x2c, 0x2f, 0x32, 0x35, + 0x38, 0x3b, 0x3e, 0x41, 0x44, 0x47, 0x4a, 0x4d, + 0x50, 0x53, 0x56, 0x59, 0x5c, 0x5f, 0x62, 0x65, + 0x68, 0x6b, 0x6e, 0x71, 0x74, 0x77, 0x7a, 0x7d, + 0x80, 0x83, 0x86, 0x89, 0x8c, 0x8f, 0x92, 0x95, + 0x98, 0x9b, 0x9e, 0xa1, 0xa4, 0xa7, 0xaa, 0xad, + 0xb0, 0xb3, 0xb6, 0xb9, 0xbc, 0xbf, 0xc2, 0xc5, + 0xc8, 0xcb, 0xce, 0xd1, 0xd4, 0xd7, 0xda, 0xdd, + 0xe0, 0xe3, 0xe6, 0xe9, 0xec, 0xef, 0xf2, 0xf5, + 0xf8, 0xfb, 0xfe, 0x01, 0x04, 0x07, 0x0a, 0x0d, + 0x10, 0x13, 0x16, 0x19, 0x1c, 0x1f, 0x22, 0x25, + 0x28, 0x2b, 0x2e, 0x31, 0x34, 0x37, 0x3a, 0x3d, + 0x40, 0x43, 0x46, 0x49, 0x4c, 0x4f, 0x52, 0x55, + 0x58, 0x5b, 0x5e, 0x61, 0x64, 0x67, 0x6a, 0x6d, + 0x70, 0x73, 0x76, 0x79, 0x7c, 0x7f, 0x82, 0x85, + 0x88, 0x8b, 0x8e, 0x91, 0x94, 0x97, 0x9a, 0x9d, + 0xa0, 0xa3, 0xa6, 0xa9, 0xac, 0xaf, 0xb2, 0xb5, + 0xb8, 0xbb, 0xbe, 0xc1, 0xc4, 0xc7, 0xca, 0xcd, + 0xd0, 0xd3, 0xd6, 0xd9, 0xdc, 0xdf, 0xe2, 0xe5, + 0xe8, 0xeb, 0xee, 0xf1, 0xf4, 0xf7, 0xfa, 0xfd, + 0x00, 0x05, 0x0a, 0x0f, 0x14, 0x19, 0x1e, 0x23, + 0x28, 0x2d, 0x32, 0x37, 0x3c, 0x41, 0x46, 0x4b, + 0x50, 0x55, 0x5a, 0x5f, 0x64, 0x69, 0x6e, 0x73, + 0x78, 0x7d, 0x82, 0x87, 0x8c, 0x91, 0x96, 0x9b, + 0xa0, 0xa5, 0xaa, 0xaf, 0xb4, 0xb9, 0xbe, 0xc3, + 0xc8, 0xcd, 0xd2, 0xd7, 0xdc, 0xe1, 0xe6, 0xeb, + 0xf0, 0xf5, 0xfa, 0xff, 0x04, 0x09, 0x0e, 0x13, + 0x18, 0x1d, 0x22, 0x27, 0x2c, 0x31, 0x36, 0x3b, + 0x40, 0x45, 0x4a, 0x4f, 0x54, 0x59, 0x5e, 0x63, + 0x68, 0x6d, 0x72, 0x77, 0x7c, 0x81, 0x86, 0x8b, + 0x90, 0x95, 0x9a, 0x9f, 0xa4, 0xa9, 0xae, 0xb3, + 0xb8, 0xbd, 0xc2, 0xc7, 0xcc, 0xd1, 0xd6, 0xdb, + 0xe0, 0xe5, 0xea, 0xef, 0xf4, 0xf9, 0xfe, 0x03, + 0x08, 0x0d, 0x12, 0x17, 0x1c, 0x21, 0x26, 0x2b, + 0x30, 0x35, 0x3a, 0x3f, 0x44, 0x49, 0x4e, 0x53, + 0x58, 0x5d, 0x62, 0x67, 0x6c, 0x71, 0x76, 0x7b, + 0x80, 0x85, 0x8a, 0x8f, 0x94, 0x99, 0x9e, 0xa3, + 0xa8, 0xad, 0xb2, 0xb7, 0xbc, 0xc1, 0xc6, 0xcb, + 0xd0, 0xd5, 0xda, 0xdf, 0xe4, 0xe9, 0xee, 0xf3, + 0xf8, 0xfd, 0x02, 0x07, 0x0c, 0x11, 0x16, 0x1b, + 0x20, 0x25, 0x2a, 0x2f, 0x34, 0x39, 0x3e, 0x43, + 0x48, 0x4d, 0x52, 0x57, 0x5c, 0x61, 0x66, 0x6b, + 0x70, 0x75, 0x7a, 0x7f, 0x84, 0x89, 0x8e, 0x93, + 0x98, 0x9d, 0xa2, 0xa7, 0xac, 0xb1, 0xb6, 0xbb, + 0xc0, 0xc5, 0xca, 0xcf, 0xd4, 0xd9, 0xde, 0xe3, + 0xe8, 0xed, 0xf2, 0xf7, 0xfc, 0x01, 0x06, 0x0b, + 0x10, 0x15, 0x1a, 0x1f, 0x24, 0x29, 0x2e, 0x33, + 0x38, 0x3d, 0x42, 0x47, 0x4c, 0x51, 0x56, 0x5b, + 0x60, 0x65, 0x6a, 0x6f, 0x74, 0x79, 0x7e, 0x83, + 0x88, 0x8d, 0x92, 0x97, 0x9c, 0xa1, 0xa6, 0xab, + 0xb0, 0xb5, 0xba, 0xbf, 0xc4, 0xc9, 0xce, 0xd3, + 0xd8, 0xdd, 0xe2, 0xe7, 0xec, 0xf1, 0xf6, 0xfb, + 0x00, 0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31, + 0x38, 0x3f, 0x46, 0x4d, 0x54, 0x5b, 0x62, 0x69, + 0x70, 0x77, 0x7e, 0x85, 0x8c, 0x93, 0x9a, 0xa1, + 0xa8, 0xaf, 0xb6, 0xbd, 0xc4, 0xcb, 0xd2, 0xd9, + 0xe0, 0xe7, 0xee, 0xf5, 0xfc, 0x03, 0x0a, 0x11, + 0x18, 0x1f, 0x26, 0x2d, 0x34, 0x3b, 0x42, 0x49, + 0x50, 0x57, 0x5e, 0x65, 0x6c, 0x73, 0x7a, 0x81, + 0x88, 0x8f, 0x96, 0x9d, 0xa4, 0xab, 0xb2, 0xb9, + 0xc0, 0xc7, 0xce, 0xd5, 0xdc, 0xe3, 0xea, 0xf1, + 0xf8, 0xff, 0x06, 0x0d, 0x14, 0x1b, 0x22, 0x29, + 0x30, 0x37, 0x3e, 0x45, 0x4c, 0x53, 0x5a, 0x61, + 0x68, 0x6f, 0x76, 0x7d, 0x84, 0x8b, 0x92, 0x99, + 0xa0, 0xa7, 0xae, 0xb5, 0xbc, 0xc3, 0xca, 0xd1, + 0xd8, 0xdf, 0xe6, 0xed, 0xf4, 0xfb, 0x02, 0x09, + 0x10, 0x17, 0x1e, 0x25, 0x2c, 0x33, 0x3a, 0x41, + 0x48, 0x4f, 0x56, 0x5d, 0x64, 0x6b, 0x72, 0x79, + 0x80, 0x87, 0x8e, 0x95, 0x9c, 0xa3, 0xaa, 0xb1, + 0xb8, 0xbf, 0xc6, 0xcd, 0xd4, 0xdb, 0xe2, 0xe9, + 0xf0, 0xf7, 0xfe, 0x05, 0x0c, 0x13, 0x1a, 0x21, + 0x28, 0x2f, 0x36, 0x3d, 0x44, 0x4b, 0x52, 0x59, + 0x60, 0x67, 0x6e, 0x75, 0x7c, 0x83, 0x8a, 0x91, + 0x98, 0x9f, 0xa6, 0xad, 0xb4, 0xbb, 0xc2, 0xc9, + 0xd0, 0xd7, 0xde, 0xe5, 0xec, 0xf3, 0xfa, 0x01, + 0x08, 0x0f, 0x16, 0x1d, 0x24, 0x2b, 0x32, 0x39, + 0x40, 0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, + 0x78, 0x7f, 0x86, 0x8d, 0x94, 0x9b, 0xa2, 0xa9, + 0xb0, 0xb7, 0xbe, 0xc5, 0xcc, 0xd3, 0xda, 0xe1, + 0xe8, 0xef, 0xf6, 0xfd, 0x04, 0x0b, 0x12, 0x19, + 0x20, 0x27, 0x2e, 0x35, 0x3c, 0x43, 0x4a, 0x51, + 0x58, 0x5f, 0x66, 0x6d, 0x74, 0x7b, 0x82, 0x89, + 0x90, 0x97, 0x9e, 0xa5, 0xac, 0xb3, 0xba, 0xc1, + 0xc8, 0xcf, 0xd6, 0xdd, 0xe4, 0xeb, 0xf2, 0xf9, + 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, + 0x48, 0x51, 0x5a, 0x63, 0x6c, 0x75, 0x7e, 0x87, + 0x90, 0x99, 0xa2, 0xab, 0xb4, 0xbd, 0xc6, 0xcf, + 0xd8, 0xe1, 0xea, 0xf3, 0xfc, 0x05, 0x0e, 0x17, + 0x20, 0x29, 0x32, 0x3b, 0x44, 0x4d, 0x56, 0x5f, + 0x68, 0x71, 0x7a, 0x83, 0x8c, 0x95, 0x9e, 0xa7, + 0xb0, 0xb9, 0xc2, 0xcb, 0xd4, 0xdd, 0xe6, 0xef, + 0xf8, 0x01, 0x0a, 0x13, 0x1c, 0x25, 0x2e, 0x37, + 0x40, 0x49, 0x52, 0x5b, 0x64, 0x6d, 0x76, 0x7f, + 0x88, 0x91, 0x9a, 0xa3, 0xac, 0xb5, 0xbe, 0xc7, + 0xd0, 0xd9, 0xe2, 0xeb, 0xf4, 0xfd, 0x06, 0x0f, + 0x18, 0x21, 0x2a, 0x33, 0x3c, 0x45, 0x4e, 0x57, + 0x60, 0x69, 0x72, 0x7b, 0x84, 0x8d, 0x96, 0x9f, + 0xa8, 0xb1, 0xba, 0xc3, 0xcc, 0xd5, 0xde, 0xe7, + 0xf0, 0xf9, 0x02, 0x0b, 0x14, 0x1d, 0x26, 0x2f, + 0x38, 0x41, 0x4a, 0x53, 0x5c, 0x65, 0x6e, 0x77, + 0x80, 0x89, 0x92, 0x9b, 0xa4, 0xad, 0xb6, 0xbf, + 0xc8, 0xd1, 0xda, 0xe3, 0xec, 0xf5, 0xfe, 0x07, + 0x10, 0x19, 0x22, 0x2b, 0x34, 0x3d, 0x46, 0x4f, + 0x58, 0x61, 0x6a, 0x73, 0x7c, 0x85, 0x8e, 0x97, + 0xa0, 0xa9, 0xb2, 0xbb, 0xc4, 0xcd, 0xd6, 0xdf, + 0xe8, 0xf1, 0xfa, 0x03, 0x0c, 0x15, 0x1e, 0x27, + 0x30, 0x39, 0x42, 0x4b, 0x54, 0x5d, 0x66, 0x6f, + 0x78, 0x81, 0x8a, 0x93, 0x9c, 0xa5, 0xae, 0xb7, + 0xc0, 0xc9, 0xd2, 0xdb, 0xe4, 0xed, 0xf6, 0xff, + 0x08, 0x11, 0x1a, 0x23, 0x2c, 0x35, 0x3e, 0x47, + 0x50, 0x59, 0x62, 0x6b, 0x74, 0x7d, 0x86, 0x8f, + 0x98, 0xa1, 0xaa, 0xb3, 0xbc, 0xc5, 0xce, 0xd7, + 0xe0, 0xe9, 0xf2, 0xfb, 0x04, 0x0d, 0x16, 0x1f, + 0x28, 0x31, 0x3a, 0x43, 0x4c, 0x55, 0x5e, 0x67, + 0x70, 0x79, 0x82, 0x8b, 0x94, 0x9d, 0xa6, 0xaf, + 0xb8, 0xc1, 0xca, 0xd3, 0xdc, 0xe5, 0xee, 0xf7, + 0x00, 0x0b, 0x16, 0x21, 0x2c, 0x37, 0x42, 0x4d, + 0x58, 0x63, 0x6e, 0x79, 0x84, 0x8f, 0x9a, 0xa5, + 0xb0, 0xbb, 0xc6, 0xd1, 0xdc, 0xe7, 0xf2, 0xfd, + 0x08, 0x13, 0x1e, 0x29, 0x34, 0x3f, 0x4a, 0x55, + 0x60, 0x6b, 0x76, 0x81, 0x8c, 0x97, 0xa2, 0xad, + 0xb8, 0xc3, 0xce, 0xd9, 0xe4, 0xef, 0xfa, 0x05, + 0x10, 0x1b, 0x26, 0x31, 0x3c, 0x47, 0x52, 0x5d, + 0x68, 0x73, 0x7e, 0x89, 0x94, 0x9f, 0xaa, 0xb5, + 0xc0, 0xcb, 0xd6, 0xe1, 0xec, 0xf7, 0x02, 0x0d, + 0x18, 0x23, 0x2e, 0x39, 0x44, 0x4f, 0x5a, 0x65, + 0x70, 0x7b, 0x86, 0x91, 0x9c, 0xa7, 0xb2, 0xbd, + 0xc8, 0xd3, 0xde, 0xe9, 0xf4, 0xff, 0x0a, 0x15, + 0x20, 0x2b, 0x36, 0x41, 0x4c, 0x57, 0x62, 0x6d, + 0x78, 0x83, 0x8e, 0x99, 0xa4, 0xaf, 0xba, 0xc5, + 0xd0, 0xdb, 0xe6, 0xf1, 0xfc, 0x07, 0x12, 0x1d, + 0x28, 0x33, 0x3e, 0x49, 0x54, 0x5f, 0x6a, 0x75, + 0x80, 0x8b, 0x96, 0xa1, 0xac, 0xb7, 0xc2, 0xcd, + 0xd8, 0xe3, 0xee, 0xf9, 0x04, 0x0f, 0x1a, 0x25, + 0x30, 0x3b, 0x46, 0x51, 0x5c, 0x67, 0x72, 0x7d, + 0x88, 0x93, 0x9e, 0xa9, 0xb4, 0xbf, 0xca, 0xd5, + 0xe0, 0xeb, 0xf6, 0x01, 0x0c, 0x17, 0x22, 0x2d, + 0x38, 0x43, 0x4e, 0x59, 0x64, 0x6f, 0x7a, 0x85, + 0x90, 0x9b, 0xa6, 0xb1, 0xbc, 0xc7, 0xd2, 0xdd, + 0xe8, 0xf3, 0xfe, 0x09, 0x14, 0x1f, 0x2a, 0x35, + 0x40, 0x4b, 0x56, 0x61, 0x6c, 0x77, 0x82, 0x8d, + 0x98, 0xa3, 0xae, 0xb9, 0xc4, 0xcf, 0xda, 0xe5, + 0xf0, 0xfb, 0x06, 0x11, 0x1c, 0x27, 0x32, 0x3d, + 0x48, 0x53, 0x5e, 0x69, 0x74, 0x7f, 0x8a, 0x95, + 0xa0, 0xab, 0xb6, 0xc1, 0xcc, 0xd7, 0xe2, 0xed, + 0xf8, 0x03, 0x0e, 0x19, 0x24, 0x2f, 0x3a, 0x45, + 0x50, 0x5b, 0x66, 0x71, 0x7c, 0x87, 0x92, 0x9d, + 0xa8, 0xb3, 0xbe, 0xc9, 0xd4, 0xdf, 0xea, 0xf5, + 0x00, 0x0d, 0x1a, 0x27, 0x34, 0x41, 0x4e, 0x5b, + 0x68, 0x75, 0x82, 0x8f, 0x9c, 0xa9, 0xb6, 0xc3, + 0xd0, 0xdd, 0xea, 0xf7, 0x04, 0x11, 0x1e, 0x2b, + 0x38, 0x45, 0x52, 0x5f, 0x6c, 0x79, 0x86, 0x93, + 0xa0, 0xad, 0xba, 0xc7, 0xd4, 0xe1, 0xee, 0xfb, + 0x08, 0x15, 0x22, 0x2f, 0x3c, 0x49, 0x56, 0x63, + 0x70, 0x7d, 0x8a, 0x97, 0xa4, 0xb1, 0xbe, 0xcb, + 0xd8, 0xe5, 0xf2, 0xff, 0x0c, 0x19, 0x26, 0x33, + 0x40, 0x4d, 0x5a, 0x67, 0x74, 0x81, 0x8e, 0x9b, + 0xa8, 0xb5, 0xc2, 0xcf, 0xdc, 0xe9, 0xf6, 0x03, + 0x10, 0x1d, 0x2a, 0x37, 0x44, 0x51, 0x5e, 0x6b, + 0x78, 0x85, 0x92, 0x9f, 0xac, 0xb9, 0xc6, 0xd3, + 0xe0, 0xed, 0xfa, 0x07, 0x14, 0x21, 0x2e, 0x3b, + 0x48, 0x55, 0x62, 0x6f, 0x7c, 0x89, 0x96, 0xa3, + 0xb0, 0xbd, 0xca, 0xd7, 0xe4, 0xf1, 0xfe, 0x0b, + 0x18, 0x25, 0x32, 0x3f, 0x4c, 0x59, 0x66, 0x73, + 0x80, 0x8d, 0x9a, 0xa7, 0xb4, 0xc1, 0xce, 0xdb, + 0xe8, 0xf5, 0x02, 0x0f, 0x1c, 0x29, 0x36, 0x43, + 0x50, 0x5d, 0x6a, 0x77, 0x84, 0x91, 0x9e, 0xab, + 0xb8, 0xc5, 0xd2, 0xdf, 0xec, 0xf9, 0x06, 0x13, + 0x20, 0x2d, 0x3a, 0x47, 0x54, 0x61, 0x6e, 0x7b, + 0x88, 0x95, 0xa2, 0xaf, 0xbc, 0xc9, 0xd6, 0xe3, + 0xf0, 0xfd, 0x0a, 0x17, 0x24, 0x31, 0x3e, 0x4b, + 0x58, 0x65, 0x72, 0x7f, 0x8c, 0x99, 0xa6, 0xb3, + 0xc0, 0xcd, 0xda, 0xe7, 0xf4, 0x01, 0x0e, 0x1b, + 0x28, 0x35, 0x42, 0x4f, 0x5c, 0x69, 0x76, 0x83, + 0x90, 0x9d, 0xaa, 0xb7, 0xc4, 0xd1, 0xde, 0xeb, + 0xf8, 0x05, 0x12, 0x1f, 0x2c, 0x39, 0x46, 0x53, + 0x60, 0x6d, 0x7a, 0x87, 0x94, 0xa1, 0xae, 0xbb, + 0xc8, 0xd5, 0xe2, 0xef, 0xfc, 0x09, 0x16, 0x23, + 0x30, 0x3d, 0x4a, 0x57, 0x64, 0x71, 0x7e, 0x8b, + 0x98, 0xa5, 0xb2, 0xbf, 0xcc, 0xd9, 0xe6, 0xf3, + 0x00, 0x0f, 0x1e, 0x2d, 0x3c, 0x4b, 0x5a, 0x69, + 0x78, 0x87, 0x96, 0xa5, 0xb4, 0xc3, 0xd2, 0xe1, + 0xf0, 0xff, 0x0e, 0x1d, 0x2c, 0x3b, 0x4a, 0x59, + 0x68, 0x77, 0x86, 0x95, 0xa4, 0xb3, 0xc2, 0xd1, + 0xe0, 0xef, 0xfe, 0x0d, 0x1c, 0x2b, 0x3a, 0x49, + 0x58, 0x67, 0x76, 0x85, 0x94, 0xa3, 0xb2, 0xc1, + 0xd0, 0xdf, 0xee, 0xfd, 0x0c, 0x1b, 0x2a, 0x39, + 0x48, 0x57, 0x66, 0x75, 0x84, 0x93, 0xa2, 0xb1, + 0xc0, 0xcf, 0xde, 0xed, 0xfc, 0x0b, 0x1a, 0x29, + 0x38, 0x47, 0x56, 0x65, 0x74, 0x83, 0x92, 0xa1, + 0xb0, 0xbf, 0xce, 0xdd, 0xec, 0xfb, 0x0a, 0x19, + 0x28, 0x37, 0x46, 0x55, 0x64, 0x73, 0x82, 0x91, + 0xa0, 0xaf, 0xbe, 0xcd, 0xdc, 0xeb, 0xfa, 0x09, + 0x18, 0x27, 0x36, 0x45, 0x54, 0x63, 0x72, 0x81, + 0x90, 0x9f, 0xae, 0xbd, 0xcc, 0xdb, 0xea, 0xf9, + 0x08, 0x17, 0x26, 0x35, 0x44, 0x53, 0x62, 0x71, + 0x80, 0x8f, 0x9e, 0xad, 0xbc, 0xcb, 0xda, 0xe9, + 0xf8, 0x07, 0x16, 0x25, 0x34, 0x43, 0x52, 0x61, + 0x70, 0x7f, 0x8e, 0x9d, 0xac, 0xbb, 0xca, 0xd9, + 0xe8, 0xf7, 0x06, 0x15, 0x24, 0x33, 0x42, 0x51, + 0x60, 0x6f, 0x7e, 0x8d, 0x9c, 0xab, 0xba, 0xc9, + 0xd8, 0xe7, 0xf6, 0x05, 0x14, 0x23, 0x32, 0x41, + 0x50, 0x5f, 0x6e, 0x7d, 0x8c, 0x9b, 0xaa, 0xb9, + 0xc8, 0xd7, 0xe6, 0xf5, 0x04, 0x13, 0x22, 0x31, + 0x40, 0x4f, 0x5e, 0x6d, 0x7c, 0x8b, 0x9a, 0xa9, + 0xb8, 0xc7, 0xd6, 0xe5, 0xf4, 0x03, 0x12, 0x21, + 0x30, 0x3f, 0x4e, 0x5d, 0x6c, 0x7b, 0x8a, 0x99, + 0xa8, 0xb7, 0xc6, 0xd5, 0xe4, 0xf3, 0x02, 0x11, + 0x20, 0x2f, 0x3e, 0x4d, 0x5c, 0x6b, 0x7a, 0x89, + 0x98, 0xa7, 0xb6, 0xc5, 0xd4, 0xe3, 0xf2, 0x01, + 0x10, 0x1f, 0x2e, 0x3d, 0x4c, 0x5b, 0x6a, 0x79, + 0x88, 0x97, 0xa6, 0xb5, 0xc4, 0xd3, 0xe2, 0xf1, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, + 0x10, 0x21, 0x32, 0x43, 0x54, 0x65, 0x76, 0x87, + 0x98, 0xa9, 0xba, 0xcb, 0xdc, 0xed, 0xfe, 0x0f, + 0x20, 0x31, 0x42, 0x53, 0x64, 0x75, 0x86, 0x97, + 0xa8, 0xb9, 0xca, 0xdb, 0xec, 0xfd, 0x0e, 0x1f, + 0x30, 0x41, 0x52, 0x63, 0x74, 0x85, 0x96, 0xa7, + 0xb8, 0xc9, 0xda, 0xeb, 0xfc, 0x0d, 0x1e, 0x2f, + 0x40, 0x51, 0x62, 0x73, 0x84, 0x95, 0xa6, 0xb7, + 0xc8, 0xd9, 0xea, 0xfb, 0x0c, 0x1d, 0x2e, 0x3f, + 0x50, 0x61, 0x72, 0x83, 0x94, 0xa5, 0xb6, 0xc7, + 0xd8, 0xe9, 0xfa, 0x0b, 0x1c, 0x2d, 0x3e, 0x4f, + 0x60, 0x71, 0x82, 0x93, 0xa4, 0xb5, 0xc6, 0xd7, + 0xe8, 0xf9, 0x0a, 0x1b, 0x2c, 0x3d, 0x4e, 0x5f, + 0x70, 0x81, 0x92, 0xa3, 0xb4, 0xc5, 0xd6, 0xe7, + 0xf8, 0x09, 0x1a, 0x2b, 0x3c, 0x4d, 0x5e, 0x6f, + 0x80, 0x91, 0xa2, 0xb3, 0xc4, 0xd5, 0xe6, 0xf7, + 0x08, 0x19, 0x2a, 0x3b, 0x4c, 0x5d, 0x6e, 0x7f, + 0x90, 0xa1, 0xb2, 0xc3, 0xd4, 0xe5, 0xf6, 0x07, + 0x18, 0x29, 0x3a, 0x4b, 0x5c, 0x6d, 0x7e, 0x8f, + 0xa0, 0xb1, 0xc2, 0xd3, 0xe4, 0xf5, 0x06, 0x17, + 0x28, 0x39, 0x4a, 0x5b, 0x6c, 0x7d, 0x8e, 0x9f, + 0xb0, 0xc1, 0xd2, 0xe3, 0xf4, 0x05, 0x16, 0x27, + 0x38, 0x49, 0x5a, 0x6b, 0x7c, 0x8d, 0x9e, 0xaf, + 0xc0, 0xd1, 0xe2, 0xf3, 0x04, 0x15, 0x26, 0x37, + 0x48, 0x59, 0x6a, 0x7b, 0x8c, 0x9d, 0xae, 0xbf, + 0xd0, 0xe1, 0xf2, 0x03, 0x14, 0x25, 0x36, 0x47, + 0x58, 0x69, 0x7a, 0x8b, 0x9c, 0xad, 0xbe, 0xcf, + 0xe0, 0xf1, 0x02, 0x13, 0x24, 0x35, 0x46, 0x57, + 0x68, 0x79, 0x8a, 0x9b, 0xac, 0xbd, 0xce, 0xdf, + 0xf0, 0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, + 0x78, 0x89, 0x9a, 0xab, 0xbc, 0xcd, 0xde, 0xef, + 0x00, 0x13, 0x26, 0x39, 0x4c, 0x5f, 0x72, 0x85, + 0x98, 0xab, 0xbe, 0xd1, 0xe4, 0xf7, 0x0a, 0x1d, + 0x30, 0x43, 0x56, 0x69, 0x7c, 0x8f, 0xa2, 0xb5, + 0xc8, 0xdb, 0xee, 0x01, 0x14, 0x27, 0x3a, 0x4d, + 0x60, 0x73, 0x86, 0x99, 0xac, 0xbf, 0xd2, 0xe5, + 0xf8, 0x0b, 0x1e, 0x31, 0x44, 0x57, 0x6a, 0x7d, + 0x90, 0xa3, 0xb6, 0xc9, 0xdc, 0xef, 0x02, 0x15, + 0x28, 0x3b, 0x4e, 0x61, 0x74, 0x87, 0x9a, 0xad, + 0xc0, 0xd3, 0xe6, 0xf9, 0x0c, 0x1f, 0x32, 0x45, + 0x58, 0x6b, 0x7e, 0x91, 0xa4, 0xb7, 0xca, 0xdd, + 0xf0, 0x03, 0x16, 0x29, 0x3c, 0x4f, 0x62, 0x75, + 0x88, 0x9b, 0xae, 0xc1, 0xd4, 0xe7, 0xfa, 0x0d, + 0x20, 0x33, 0x46, 0x59, 0x6c, 0x7f, 0x92, 0xa5, + 0xb8, 0xcb, 0xde, 0xf1, 0x04, 0x17, 0x2a, 0x3d, + 0x50, 0x63, 0x76, 0x89, 0x9c, 0xaf, 0xc2, 0xd5, + 0xe8, 0xfb, 0x0e, 0x21, 0x34, 0x47, 0x5a, 0x6d, + 0x80, 0x93, 0xa6, 0xb9, 0xcc, 0xdf, 0xf2, 0x05, + 0x18, 0x2b, 0x3e, 0x51, 0x64, 0x77, 0x8a, 0x9d, + 0xb0, 0xc3, 0xd6, 0xe9, 0xfc, 0x0f, 0x22, 0x35, + 0x48, 0x5b, 0x6e, 0x81, 0x94, 0xa7, 0xba, 0xcd, + 0xe0, 0xf3, 0x06, 0x19, 0x2c, 0x3f, 0x52, 0x65, + 0x78, 0x8b, 0x9e, 0xb1, 0xc4, 0xd7, 0xea, 0xfd, + 0x10, 0x23, 0x36, 0x49, 0x5c, 0x6f, 0x82, 0x95, + 0xa8, 0xbb, 0xce, 0xe1, 0xf4, 0x07, 0x1a, 0x2d, + 0x40, 0x53, 0x66, 0x79, 0x8c, 0x9f, 0xb2, 0xc5, + 0xd8, 0xeb, 0xfe, 0x11, 0x24, 0x37, 0x4a, 0x5d, + 0x70, 0x83, 0x96, 0xa9, 0xbc, 0xcf, 0xe2, 0xf5, + 0x08, 0x1b, 0x2e, 0x41, 0x54, 0x67, 0x7a, 0x8d, + 0xa0, 0xb3, 0xc6, 0xd9, 0xec, 0xff, 0x12, 0x25, + 0x38, 0x4b, 0x5e, 0x71, 0x84, 0x97, 0xaa, 0xbd, + 0xd0, 0xe3, 0xf6, 0x09, 0x1c, 0x2f, 0x42, 0x55, + 0x68, 0x7b, 0x8e, 0xa1, 0xb4, 0xc7, 0xda, 0xed, + 0x00, 0x15, 0x2a, 0x3f, 0x54, 0x69, 0x7e, 0x93, + 0xa8, 0xbd, 0xd2, 0xe7, 0xfc, 0x11, 0x26, 0x3b, + 0x50, 0x65, 0x7a, 0x8f, 0xa4, 0xb9, 0xce, 0xe3, + 0xf8, 0x0d, 0x22, 0x37, 0x4c, 0x61, 0x76, 0x8b, + 0xa0, 0xb5, 0xca, 0xdf, 0xf4, 0x09, 0x1e, 0x33, + 0x48, 0x5d, 0x72, 0x87, 0x9c, 0xb1, 0xc6, 0xdb, + 0xf0, 0x05, 0x1a, 0x2f, 0x44, 0x59, 0x6e, 0x83, + 0x98, 0xad, 0xc2, 0xd7, 0xec, 0x01, 0x16, 0x2b, + 0x40, 0x55, 0x6a, 0x7f, 0x94, 0xa9, 0xbe, 0xd3, + 0xe8, 0xfd, 0x12, 0x27, 0x3c, 0x51, 0x66, 0x7b, + 0x90, 0xa5, 0xba, 0xcf, 0xe4, 0xf9, 0x0e, 0x23, + 0x38, 0x4d, 0x62, 0x77, 0x8c, 0xa1, 0xb6, 0xcb, + 0xe0, 0xf5, 0x0a, 0x1f, 0x34, 0x49, 0x5e, 0x73, + 0x88, 0x9d, 0xb2, 0xc7, 0xdc, 0xf1, 0x06, 0x1b, + 0x30, 0x45, 0x5a, 0x6f, 0x84, 0x99, 0xae, 0xc3, + 0xd8, 0xed, 0x02, 0x17, 0x2c, 0x41, 0x56, 0x6b, + 0x80, 0x95, 0xaa, 0xbf, 0xd4, 0xe9, 0xfe, 0x13, + 0x28, 0x3d, 0x52, 0x67, 0x7c, 0x91, 0xa6, 0xbb, + 0xd0, 0xe5, 0xfa, 0x0f, 0x24, 0x39, 0x4e, 0x63, + 0x78, 0x8d, 0xa2, 0xb7, 0xcc, 0xe1, 0xf6, 0x0b, + 0x20, 0x35, 0x4a, 0x5f, 0x74, 0x89, 0x9e, 0xb3, + 0xc8, 0xdd, 0xf2, 0x07, 0x1c, 0x31, 0x46, 0x5b, + 0x70, 0x85, 0x9a, 0xaf, 0xc4, 0xd9, 0xee, 0x03, + 0x18, 0x2d, 0x42, 0x57, 0x6c, 0x81, 0x96, 0xab, + 0xc0, 0xd5, 0xea, 0xff, 0x14, 0x29, 0x3e, 0x53, + 0x68, 0x7d, 0x92, 0xa7, 0xbc, 0xd1, 0xe6, 0xfb, + 0x10, 0x25, 0x3a, 0x4f, 0x64, 0x79, 0x8e, 0xa3, + 0xb8, 0xcd, 0xe2, 0xf7, 0x0c, 0x21, 0x36, 0x4b, + 0x60, 0x75, 0x8a, 0x9f, 0xb4, 0xc9, 0xde, 0xf3, + 0x08, 0x1d, 0x32, 0x47, 0x5c, 0x71, 0x86, 0x9b, + 0xb0, 0xc5, 0xda, 0xef, 0x04, 0x19, 0x2e, 0x43, + 0x58, 0x6d, 0x82, 0x97, 0xac, 0xc1, 0xd6, 0xeb, + 0x00, 0x17, 0x2e, 0x45, 0x5c, 0x73, 0x8a, 0xa1, + 0xb8, 0xcf, 0xe6, 0xfd, 0x14, 0x2b, 0x42, 0x59, + 0x70, 0x87, 0x9e, 0xb5, 0xcc, 0xe3, 0xfa, 0x11, + 0x28, 0x3f, 0x56, 0x6d, 0x84, 0x9b, 0xb2, 0xc9, + 0xe0, 0xf7, 0x0e, 0x25, 0x3c, 0x53, 0x6a, 0x81, + 0x98, 0xaf, 0xc6, 0xdd, 0xf4, 0x0b, 0x22, 0x39, + 0x50, 0x67, 0x7e, 0x95, 0xac, 0xc3, 0xda, 0xf1, + 0x08, 0x1f, 0x36, 0x4d, 0x64, 0x7b, 0x92, 0xa9, + 0xc0, 0xd7, 0xee, 0x05, 0x1c, 0x33, 0x4a, 0x61, + 0x78, 0x8f, 0xa6, 0xbd, 0xd4, 0xeb, 0x02, 0x19, + 0x30, 0x47, 0x5e, 0x75, 0x8c, 0xa3, 0xba, 0xd1, + 0xe8, 0xff, 0x16, 0x2d, 0x44, 0x5b, 0x72, 0x89, + 0xa0, 0xb7, 0xce, 0xe5, 0xfc, 0x13, 0x2a, 0x41, + 0x58, 0x6f, 0x86, 0x9d, 0xb4, 0xcb, 0xe2, 0xf9, + 0x10, 0x27, 0x3e, 0x55, 0x6c, 0x83, 0x9a, 0xb1, + 0xc8, 0xdf, 0xf6, 0x0d, 0x24, 0x3b, 0x52, 0x69, + 0x80, 0x97, 0xae, 0xc5, 0xdc, 0xf3, 0x0a, 0x21, + 0x38, 0x4f, 0x66, 0x7d, 0x94, 0xab, 0xc2, 0xd9, + 0xf0, 0x07, 0x1e, 0x35, 0x4c, 0x63, 0x7a, 0x91, + 0xa8, 0xbf, 0xd6, 0xed, 0x04, 0x1b, 0x32, 0x49, + 0x60, 0x77, 0x8e, 0xa5, 0xbc, 0xd3, 0xea, 0x01, + 0x18, 0x2f, 0x46, 0x5d, 0x74, 0x8b, 0xa2, 0xb9, + 0xd0, 0xe7, 0xfe, 0x15, 0x2c, 0x43, 0x5a, 0x71, + 0x88, 0x9f, 0xb6, 0xcd, 0xe4, 0xfb, 0x12, 0x29, + 0x40, 0x57, 0x6e, 0x85, 0x9c, 0xb3, 0xca, 0xe1, + 0xf8, 0x0f, 0x26, 0x3d, 0x54, 0x6b, 0x82, 0x99, + 0xb0, 0xc7, 0xde, 0xf5, 0x0c, 0x23, 0x3a, 0x51, + 0x68, 0x7f, 0x96, 0xad, 0xc4, 0xdb, 0xf2, 0x09, + 0x20, 0x37, 0x4e, 0x65, 0x7c, 0x93, 0xaa, 0xc1, + 0xd8, 0xef, 0x06, 0x1d, 0x34, 0x4b, 0x62, 0x79, + 0x90, 0xa7, 0xbe, 0xd5, 0xec, 0x03, 0x1a, 0x31, + 0x48, 0x5f, 0x76, 0x8d, 0xa4, 0xbb, 0xd2, 0xe9, + 0x00, 0x19, 0x32, 0x4b, 0x64, 0x7d, 0x96, 0xaf, + 0xc8, 0xe1, 0xfa, 0x13, 0x2c, 0x45, 0x5e, 0x77, + 0x90, 0xa9, 0xc2, 0xdb, 0xf4, 0x0d, 0x26, 0x3f, + 0x58, 0x71, 0x8a, 0xa3, 0xbc, 0xd5, 0xee, 0x07, + 0x20, 0x39, 0x52, 0x6b, 0x84, 0x9d, 0xb6, 0xcf, + 0xe8, 0x01, 0x1a, 0x33, 0x4c, 0x65, 0x7e, 0x97, + 0xb0, 0xc9, 0xe2, 0xfb, 0x14, 0x2d, 0x46, 0x5f, + 0x78, 0x91, 0xaa, 0xc3, 0xdc, 0xf5, 0x0e, 0x27, + 0x40, 0x59, 0x72, 0x8b, 0xa4, 0xbd, 0xd6, 0xef, + 0x08, 0x21, 0x3a, 0x53, 0x6c, 0x85, 0x9e, 0xb7, + 0xd0, 0xe9, 0x02, 0x1b, 0x34, 0x4d, 0x66, 0x7f, + 0x98, 0xb1, 0xca, 0xe3, 0xfc, 0x15, 0x2e, 0x47, + 0x60, 0x79, 0x92, 0xab, 0xc4, 0xdd, 0xf6, 0x0f, + 0x28, 0x41, 0x5a, 0x73, 0x8c, 0xa5, 0xbe, 0xd7, + 0xf0, 0x09, 0x22, 0x3b, 0x54, 0x6d, 0x86, 0x9f, + 0xb8, 0xd1, 0xea, 0x03, 0x1c, 0x35, 0x4e, 0x67, + 0x80, 0x99, 0xb2, 0xcb, 0xe4, 0xfd, 0x16, 0x2f, + 0x48, 0x61, 0x7a, 0x93, 0xac, 0xc5, 0xde, 0xf7, + 0x10, 0x29, 0x42, 0x5b, 0x74, 0x8d, 0xa6, 0xbf, + 0xd8, 0xf1, 0x0a, 0x23, 0x3c, 0x55, 0x6e, 0x87, + 0xa0, 0xb9, 0xd2, 0xeb, 0x04, 0x1d, 0x36, 0x4f, + 0x68, 0x81, 0x9a, 0xb3, 0xcc, 0xe5, 0xfe, 0x17, + 0x30, 0x49, 0x62, 0x7b, 0x94, 0xad, 0xc6, 0xdf, + 0xf8, 0x11, 0x2a, 0x43, 0x5c, 0x75, 0x8e, 0xa7, + 0xc0, 0xd9, 0xf2, 0x0b, 0x24, 0x3d, 0x56, 0x6f, + 0x88, 0xa1, 0xba, 0xd3, 0xec, 0x05, 0x1e, 0x37, + 0x50, 0x69, 0x82, 0x9b, 0xb4, 0xcd, 0xe6, 0xff, + 0x18, 0x31, 0x4a, 0x63, 0x7c, 0x95, 0xae, 0xc7, + 0xe0, 0xf9, 0x12, 0x2b, 0x44, 0x5d, 0x76, 0x8f, + 0xa8, 0xc1, 0xda, 0xf3, 0x0c, 0x25, 0x3e, 0x57, + 0x70, 0x89, 0xa2, 0xbb, 0xd4, 0xed, 0x06, 0x1f, + 0x38, 0x51, 0x6a, 0x83, 0x9c, 0xb5, 0xce, 0xe7, + 0x00, 0x1b, 0x36, 0x51, 0x6c, 0x87, 0xa2, 0xbd, + 0xd8, 0xf3, 0x0e, 0x29, 0x44, 0x5f, 0x7a, 0x95, + 0xb0, 0xcb, 0xe6, 0x01, 0x1c, 0x37, 0x52, 0x6d, + 0x88, 0xa3, 0xbe, 0xd9, 0xf4, 0x0f, 0x2a, 0x45, + 0x60, 0x7b, 0x96, 0xb1, 0xcc, 0xe7, 0x02, 0x1d, + 0x38, 0x53, 0x6e, 0x89, 0xa4, 0xbf, 0xda, 0xf5, + 0x10, 0x2b, 0x46, 0x61, 0x7c, 0x97, 0xb2, 0xcd, + 0xe8, 0x03, 0x1e, 0x39, 0x54, 0x6f, 0x8a, 0xa5, + 0xc0, 0xdb, 0xf6, 0x11, 0x2c, 0x47, 0x62, 0x7d, + 0x98, 0xb3, 0xce, 0xe9, 0x04, 0x1f, 0x3a, 0x55, + 0x70, 0x8b, 0xa6, 0xc1, 0xdc, 0xf7, 0x12, 0x2d, + 0x48, 0x63, 0x7e, 0x99, 0xb4, 0xcf, 0xea, 0x05, + 0x20, 0x3b, 0x56, 0x71, 0x8c, 0xa7, 0xc2, 0xdd, + 0xf8, 0x13, 0x2e, 0x49, 0x64, 0x7f, 0x9a, 0xb5, + 0xd0, 0xeb, 0x06, 0x21, 0x3c, 0x57, 0x72, 0x8d, + 0xa8, 0xc3, 0xde, 0xf9, 0x14, 0x2f, 0x4a, 0x65, + 0x80, 0x9b, 0xb6, 0xd1, 0xec, 0x07, 0x22, 0x3d, + 0x58, 0x73, 0x8e, 0xa9, 0xc4, 0xdf, 0xfa, 0x15, + 0x30, 0x4b, 0x66, 0x81, 0x9c, 0xb7, 0xd2, 0xed, + 0x08, 0x23, 0x3e, 0x59, 0x74, 0x8f, 0xaa, 0xc5, + 0xe0, 0xfb, 0x16, 0x31, 0x4c, 0x67, 0x82, 0x9d, + 0xb8, 0xd3, 0xee, 0x09, 0x24, 0x3f, 0x5a, 0x75, + 0x90, 0xab, 0xc6, 0xe1, 0xfc, 0x17, 0x32, 0x4d, + 0x68, 0x83, 0x9e, 0xb9, 0xd4, 0xef, 0x0a, 0x25, + 0x40, 0x5b, 0x76, 0x91, 0xac, 0xc7, 0xe2, 0xfd, + 0x18, 0x33, 0x4e, 0x69, 0x84, 0x9f, 0xba, 0xd5, + 0xf0, 0x0b, 0x26, 0x41, 0x5c, 0x77, 0x92, 0xad, + 0xc8, 0xe3, 0xfe, 0x19, 0x34, 0x4f, 0x6a, 0x85, + 0xa0, 0xbb, 0xd6, 0xf1, 0x0c, 0x27, 0x42, 0x5d, + 0x78, 0x93, 0xae, 0xc9, 0xe4, 0xff, 0x1a, 0x35, + 0x50, 0x6b, 0x86, 0xa1, 0xbc, 0xd7, 0xf2, 0x0d, + 0x28, 0x43, 0x5e, 0x79, 0x94, 0xaf, 0xca, 0xe5, + 0x00, 0x1d, 0x3a, 0x57, 0x74, 0x91, 0xae, 0xcb, + 0xe8, 0x05, 0x22, 0x3f, 0x5c, 0x79, 0x96, 0xb3, + 0xd0, 0xed, 0x0a, 0x27, 0x44, 0x61, 0x7e, 0x9b, + 0xb8, 0xd5, 0xf2, 0x0f, 0x2c, 0x49, 0x66, 0x83, + 0xa0, 0xbd, 0xda, 0xf7, 0x14, 0x31, 0x4e, 0x6b, + 0x88, 0xa5, 0xc2, 0xdf, 0xfc, 0x19, 0x36, 0x53, + 0x70, 0x8d, 0xaa, 0xc7, 0xe4, 0x01, 0x1e, 0x3b, + 0x58, 0x75, 0x92, 0xaf, 0xcc, 0xe9, 0x06, 0x23, + 0x40, 0x5d, 0x7a, 0x97, 0xb4, 0xd1, 0xee, 0x0b, + 0x28, 0x45, 0x62, 0x7f, 0x9c, 0xb9, 0xd6, 0xf3, + 0x10, 0x2d, 0x4a, 0x67, 0x84, 0xa1, 0xbe, 0xdb, + 0xf8, 0x15, 0x32, 0x4f, 0x6c, 0x89, 0xa6, 0xc3, + 0xe0, 0xfd, 0x1a, 0x37, 0x54, 0x71, 0x8e, 0xab, + 0xc8, 0xe5, 0x02, 0x1f, 0x3c, 0x59, 0x76, 0x93, + 0xb0, 0xcd, 0xea, 0x07, 0x24, 0x41, 0x5e, 0x7b, + 0x98, 0xb5, 0xd2, 0xef, 0x0c, 0x29, 0x46, 0x63, + 0x80, 0x9d, 0xba, 0xd7, 0xf4, 0x11, 0x2e, 0x4b, + 0x68, 0x85, 0xa2, 0xbf, 0xdc, 0xf9, 0x16, 0x33, + 0x50, 0x6d, 0x8a, 0xa7, 0xc4, 0xe1, 0xfe, 0x1b, + 0x38, 0x55, 0x72, 0x8f, 0xac, 0xc9, 0xe6, 0x03, + 0x20, 0x3d, 0x5a, 0x77, 0x94, 0xb1, 0xce, 0xeb, + 0x08, 0x25, 0x42, 0x5f, 0x7c, 0x99, 0xb6, 0xd3, + 0xf0, 0x0d, 0x2a, 0x47, 0x64, 0x81, 0x9e, 0xbb, + 0xd8, 0xf5, 0x12, 0x2f, 0x4c, 0x69, 0x86, 0xa3, + 0xc0, 0xdd, 0xfa, 0x17, 0x34, 0x51, 0x6e, 0x8b, + 0xa8, 0xc5, 0xe2, 0xff, 0x1c, 0x39, 0x56, 0x73, + 0x90, 0xad, 0xca, 0xe7, 0x04, 0x21, 0x3e, 0x5b, + 0x78, 0x95, 0xb2, 0xcf, 0xec, 0x09, 0x26, 0x43, + 0x60, 0x7d, 0x9a, 0xb7, 0xd4, 0xf1, 0x0e, 0x2b, + 0x48, 0x65, 0x82, 0x9f, 0xbc, 0xd9, 0xf6, 0x13, + 0x30, 0x4d, 0x6a, 0x87, 0xa4, 0xc1, 0xde, 0xfb, + 0x18, 0x35, 0x52, 0x6f, 0x8c, 0xa9, 0xc6, 0xe3, + 0x00, 0x1f, 0x3e, 0x5d, 0x7c, 0x9b, 0xba, 0xd9, + 0xf8, 0x17, 0x36, 0x55, 0x74, 0x93, 0xb2, 0xd1, + 0xf0, 0x0f, 0x2e, 0x4d, 0x6c, 0x8b, 0xaa, 0xc9, + 0xe8, 0x07, 0x26, 0x45, 0x64, 0x83, 0xa2, 0xc1, + 0xe0, 0xff, 0x1e, 0x3d, 0x5c, 0x7b, 0x9a, 0xb9, + 0xd8, 0xf7, 0x16, 0x35, 0x54, 0x73, 0x92, 0xb1, + 0xd0, 0xef, 0x0e, 0x2d, 0x4c, 0x6b, 0x8a, 0xa9, + 0xc8, 0xe7, 0x06, 0x25, 0x44, 0x63, 0x82, 0xa1, + 0xc0, 0xdf, 0xfe, 0x1d, 0x3c, 0x5b, 0x7a, 0x99, + 0xb8, 0xd7, 0xf6, 0x15, 0x34, 0x53, 0x72, 0x91, + 0xb0, 0xcf, 0xee, 0x0d, 0x2c, 0x4b, 0x6a, 0x89, + 0xa8, 0xc7, 0xe6, 0x05, 0x24, 0x43, 0x62, 0x81, + 0xa0, 0xbf, 0xde, 0xfd, 0x1c, 0x3b, 0x5a, 0x79, + 0x98, 0xb7, 0xd6, 0xf5, 0x14, 0x33, 0x52, 0x71, + 0x90, 0xaf, 0xce, 0xed, 0x0c, 0x2b, 0x4a, 0x69, + 0x88, 0xa7, 0xc6, 0xe5, 0x04, 0x23, 0x42, 0x61, + 0x80, 0x9f, 0xbe, 0xdd, 0xfc, 0x1b, 0x3a, 0x59, + 0x78, 0x97, 0xb6, 0xd5, 0xf4, 0x13, 0x32, 0x51, + 0x70, 0x8f, 0xae, 0xcd, 0xec, 0x0b, 0x2a, 0x49, + 0x68, 0x87, 0xa6, 0xc5, 0xe4, 0x03, 0x22, 0x41, + 0x60, 0x7f, 0x9e, 0xbd, 0xdc, 0xfb, 0x1a, 0x39, + 0x58, 0x77, 0x96, 0xb5, 0xd4, 0xf3, 0x12, 0x31, + 0x50, 0x6f, 0x8e, 0xad, 0xcc, 0xeb, 0x0a, 0x29, + 0x48, 0x67, 0x86, 0xa5, 0xc4, 0xe3, 0x02, 0x21, + 0x40, 0x5f, 0x7e, 0x9d, 0xbc, 0xdb, 0xfa, 0x19, + 0x38, 0x57, 0x76, 0x95, 0xb4, 0xd3, 0xf2, 0x11, + 0x30, 0x4f, 0x6e, 0x8d, 0xac, 0xcb, 0xea, 0x09, + 0x28, 0x47, 0x66, 0x85, 0xa4, 0xc3, 0xe2, 0x01, + 0x20, 0x3f, 0x5e, 0x7d, 0x9c, 0xbb, 0xda, 0xf9, + 0x18, 0x37, 0x56, 0x75, 0x94, 0xb3, 0xd2, 0xf1, + 0x10, 0x2f, 0x4e, 0x6d, 0x8c, 0xab, 0xca, 0xe9, + 0x08, 0x27, 0x46, 0x65, 0x84, 0xa3, 0xc2, 0xe1, + 0x00, 0x21, 0x42, 0x63, + }, + .ilen = 4100, + .result = { + 0xb5, 0x81, 0xf5, 0x64, 0x18, 0x73, 0xe3, 0xf0, + 0x4c, 0x13, 0xf2, 0x77, 0x18, 0x60, 0x65, 0x5e, + 0x29, 0x01, 0xce, 0x98, 0x55, 0x53, 0xf9, 0x0c, + 0x2a, 0x08, 0xd5, 0x09, 0xb3, 0x57, 0x55, 0x56, + 0xc5, 0xe9, 0x56, 0x90, 0xcb, 0x6a, 0xa3, 0xc0, + 0xff, 0xc4, 0x79, 0xb4, 0xd2, 0x97, 0x5d, 0xc4, + 0x43, 0xd1, 0xfe, 0x94, 0x7b, 0x88, 0x06, 0x5a, + 0xb2, 0x9e, 0x2c, 0xfc, 0x44, 0x03, 0xb7, 0x90, + 0xa0, 0xc1, 0xba, 0x6a, 0x33, 0xb8, 0xc7, 0xb2, + 0x9d, 0xe1, 0x12, 0x4f, 0xc0, 0x64, 0xd4, 0x01, + 0xfe, 0x8c, 0x7a, 0x66, 0xf7, 0xe6, 0x5a, 0x91, + 0xbb, 0xde, 0x56, 0x86, 0xab, 0x65, 0x21, 0x30, + 0x00, 0x84, 0x65, 0x24, 0xa5, 0x7d, 0x85, 0xb4, + 0xe3, 0x17, 0xed, 0x3a, 0xb7, 0x6f, 0xb4, 0x0b, + 0x0b, 0xaf, 0x15, 0xae, 0x5a, 0x8f, 0xf2, 0x0c, + 0x2f, 0x27, 0xf4, 0x09, 0xd8, 0xd2, 0x96, 0xb7, + 0x71, 0xf2, 0xc5, 0x99, 0x4d, 0x7e, 0x7f, 0x75, + 0x77, 0x89, 0x30, 0x8b, 0x59, 0xdb, 0xa2, 0xb2, + 0xa0, 0xf3, 0x19, 0x39, 0x2b, 0xc5, 0x7e, 0x3f, + 0x4f, 0xd9, 0xd3, 0x56, 0x28, 0x97, 0x44, 0xdc, + 0xc0, 0x8b, 0x77, 0x24, 0xd9, 0x52, 0xe7, 0xc5, + 0xaf, 0xf6, 0x7d, 0x59, 0xb2, 0x44, 0x05, 0x1d, + 0xb1, 0xb0, 0x11, 0xa5, 0x0f, 0xec, 0x33, 0xe1, + 0x6d, 0x1b, 0x4e, 0x1f, 0xff, 0x57, 0x91, 0xb4, + 0x5b, 0x9a, 0x96, 0xc5, 0x53, 0xbc, 0xae, 0x20, + 0x3c, 0xbb, 0x14, 0xe2, 0xe8, 0x22, 0x33, 0xc1, + 0x5e, 0x76, 0x9e, 0x46, 0x99, 0xf6, 0x2a, 0x15, + 0xc6, 0x97, 0x02, 0xa0, 0x66, 0x43, 0xd1, 0xa6, + 0x31, 0xa6, 0x9f, 0xfb, 0xf4, 0xd3, 0x69, 0xe5, + 0xcd, 0x76, 0x95, 0xb8, 0x7a, 0x82, 0x7f, 0x21, + 0x45, 0xff, 0x3f, 0xce, 0x55, 0xf6, 0x95, 0x10, + 0x08, 0x77, 0x10, 0x43, 0xc6, 0xf3, 0x09, 0xe5, + 0x68, 0xe7, 0x3c, 0xad, 0x00, 0x52, 0x45, 0x0d, + 0xfe, 0x2d, 0xc6, 0xc2, 0x94, 0x8c, 0x12, 0x1d, + 0xe6, 0x25, 0xae, 0x98, 0x12, 0x8e, 0x19, 0x9c, + 0x81, 0x68, 0xb1, 0x11, 0xf6, 0x69, 0xda, 0xe3, + 0x62, 0x08, 0x18, 0x7a, 0x25, 0x49, 0x28, 0xac, + 0xba, 0x71, 0x12, 0x0b, 0xe4, 0xa2, 0xe5, 0xc7, + 0x5d, 0x8e, 0xec, 0x49, 0x40, 0x21, 0xbf, 0x5a, + 0x98, 0xf3, 0x02, 0x68, 0x55, 0x03, 0x7f, 0x8a, + 0xe5, 0x94, 0x0c, 0x32, 0x5c, 0x07, 0x82, 0x63, + 0xaf, 0x6f, 0x91, 0x40, 0x84, 0x8e, 0x52, 0x25, + 0xd0, 0xb0, 0x29, 0x53, 0x05, 0xe2, 0x50, 0x7a, + 0x34, 0xeb, 0xc9, 0x46, 0x20, 0xa8, 0x3d, 0xde, + 0x7f, 0x16, 0x5f, 0x36, 0xc5, 0x2e, 0xdc, 0xd1, + 0x15, 0x47, 0xc7, 0x50, 0x40, 0x6d, 0x91, 0xc5, + 0xe7, 0x93, 0x95, 0x1a, 0xd3, 0x57, 0xbc, 0x52, + 0x33, 0xee, 0x14, 0x19, 0x22, 0x52, 0x89, 0xa7, + 0x4a, 0x25, 0x56, 0x77, 0x4b, 0xca, 0xcf, 0x0a, + 0xe1, 0xf5, 0x35, 0x85, 0x30, 0x7e, 0x59, 0x4a, + 0xbd, 0x14, 0x5b, 0xdf, 0xe3, 0x46, 0xcb, 0xac, + 0x1f, 0x6c, 0x96, 0x0e, 0xf4, 0x81, 0xd1, 0x99, + 0xca, 0x88, 0x63, 0x3d, 0x02, 0x58, 0x6b, 0xa9, + 0xe5, 0x9f, 0xb3, 0x00, 0xb2, 0x54, 0xc6, 0x74, + 0x1c, 0xbf, 0x46, 0xab, 0x97, 0xcc, 0xf8, 0x54, + 0x04, 0x07, 0x08, 0x52, 0xe6, 0xc0, 0xda, 0x93, + 0x74, 0x7d, 0x93, 0x99, 0x5d, 0x78, 0x68, 0xa6, + 0x2e, 0x6b, 0xd3, 0x6a, 0x69, 0xcc, 0x12, 0x6b, + 0xd4, 0xc7, 0xa5, 0xc6, 0xe7, 0xf6, 0x03, 0x04, + 0x5d, 0xcd, 0x61, 0x5e, 0x17, 0x40, 0xdc, 0xd1, + 0x5c, 0xf5, 0x08, 0xdf, 0x5c, 0x90, 0x85, 0xa4, + 0xaf, 0xf6, 0x78, 0xbb, 0x0d, 0xf1, 0xf4, 0xa4, + 0x54, 0x26, 0x72, 0x9e, 0x61, 0xfa, 0x86, 0xcf, + 0xe8, 0x9e, 0xa1, 0xe0, 0xc7, 0x48, 0x23, 0xae, + 0x5a, 0x90, 0xae, 0x75, 0x0a, 0x74, 0x18, 0x89, + 0x05, 0xb1, 0x92, 0xb2, 0x7f, 0xd0, 0x1b, 0xa6, + 0x62, 0x07, 0x25, 0x01, 0xc7, 0xc2, 0x4f, 0xf9, + 0xe8, 0xfe, 0x63, 0x95, 0x80, 0x07, 0xb4, 0x26, + 0xcc, 0xd1, 0x26, 0xb6, 0xc4, 0x3f, 0x9e, 0xcb, + 0x8e, 0x3b, 0x2e, 0x44, 0x16, 0xd3, 0x10, 0x9a, + 0x95, 0x08, 0xeb, 0xc8, 0xcb, 0xeb, 0xbf, 0x6f, + 0x0b, 0xcd, 0x1f, 0xc8, 0xca, 0x86, 0xaa, 0xec, + 0x33, 0xe6, 0x69, 0xf4, 0x45, 0x25, 0x86, 0x3a, + 0x22, 0x94, 0x4f, 0x00, 0x23, 0x6a, 0x44, 0xc2, + 0x49, 0x97, 0x33, 0xab, 0x36, 0x14, 0x0a, 0x70, + 0x24, 0xc3, 0xbe, 0x04, 0x3b, 0x79, 0xa0, 0xf9, + 0xb8, 0xe7, 0x76, 0x29, 0x22, 0x83, 0xd7, 0xf2, + 0x94, 0xf4, 0x41, 0x49, 0xba, 0x5f, 0x7b, 0x07, + 0xb5, 0xfb, 0xdb, 0x03, 0x1a, 0x9f, 0xb6, 0x4c, + 0xc2, 0x2e, 0x37, 0x40, 0x49, 0xc3, 0x38, 0x16, + 0xe2, 0x4f, 0x77, 0x82, 0xb0, 0x68, 0x4c, 0x71, + 0x1d, 0x57, 0x61, 0x9c, 0xd9, 0x4e, 0x54, 0x99, + 0x47, 0x13, 0x28, 0x73, 0x3c, 0xbb, 0x00, 0x90, + 0xf3, 0x4d, 0xc9, 0x0e, 0xfd, 0xe7, 0xb1, 0x71, + 0xd3, 0x15, 0x79, 0xbf, 0xcc, 0x26, 0x2f, 0xbd, + 0xad, 0x6c, 0x50, 0x69, 0x6c, 0x3e, 0x6d, 0x80, + 0x9a, 0xea, 0x78, 0xaf, 0x19, 0xb2, 0x0d, 0x4d, + 0xad, 0x04, 0x07, 0xae, 0x22, 0x90, 0x4a, 0x93, + 0x32, 0x0e, 0x36, 0x9b, 0x1b, 0x46, 0xba, 0x3b, + 0xb4, 0xac, 0xc6, 0xd1, 0xa2, 0x31, 0x53, 0x3b, + 0x2a, 0x3d, 0x45, 0xfe, 0x03, 0x61, 0x10, 0x85, + 0x17, 0x69, 0xa6, 0x78, 0xcc, 0x6c, 0x87, 0x49, + 0x53, 0xf9, 0x80, 0x10, 0xde, 0x80, 0xa2, 0x41, + 0x6a, 0xc3, 0x32, 0x02, 0xad, 0x6d, 0x3c, 0x56, + 0x00, 0x71, 0x51, 0x06, 0xa7, 0xbd, 0xfb, 0xef, + 0x3c, 0xb5, 0x9f, 0xfc, 0x48, 0x7d, 0x53, 0x7c, + 0x66, 0xb0, 0x49, 0x23, 0xc4, 0x47, 0x10, 0x0e, + 0xe5, 0x6c, 0x74, 0x13, 0xe6, 0xc5, 0x3f, 0xaa, + 0xde, 0xff, 0x07, 0x44, 0xdd, 0x56, 0x1b, 0xad, + 0x09, 0x77, 0xfb, 0x5b, 0x12, 0xb8, 0x0d, 0x38, + 0x17, 0x37, 0x35, 0x7b, 0x9b, 0xbc, 0xfe, 0xd4, + 0x7e, 0x8b, 0xda, 0x7e, 0x5b, 0x04, 0xa7, 0x22, + 0xa7, 0x31, 0xa1, 0x20, 0x86, 0xc7, 0x1b, 0x99, + 0xdb, 0xd1, 0x89, 0xf4, 0x94, 0xa3, 0x53, 0x69, + 0x8d, 0xe7, 0xe8, 0x74, 0x11, 0x8d, 0x74, 0xd6, + 0x07, 0x37, 0x91, 0x9f, 0xfd, 0x67, 0x50, 0x3a, + 0xc9, 0xe1, 0xf4, 0x36, 0xd5, 0xa0, 0x47, 0xd1, + 0xf9, 0xe5, 0x39, 0xa3, 0x31, 0xac, 0x07, 0x36, + 0x23, 0xf8, 0x66, 0x18, 0x14, 0x28, 0x34, 0x0f, + 0xb8, 0xd0, 0xe7, 0x29, 0xb3, 0x04, 0x4b, 0x55, + 0x01, 0x41, 0xb2, 0x75, 0x8d, 0xcb, 0x96, 0x85, + 0x3a, 0xfb, 0xab, 0x2b, 0x9e, 0xfa, 0x58, 0x20, + 0x44, 0x1f, 0xc0, 0x14, 0x22, 0x75, 0x61, 0xe8, + 0xaa, 0x19, 0xcf, 0xf1, 0x82, 0x56, 0xf4, 0xd7, + 0x78, 0x7b, 0x3d, 0x5f, 0xb3, 0x9e, 0x0b, 0x8a, + 0x57, 0x50, 0xdb, 0x17, 0x41, 0x65, 0x4d, 0xa3, + 0x02, 0xc9, 0x9c, 0x9c, 0x53, 0xfb, 0x39, 0x39, + 0x9b, 0x1d, 0x72, 0x24, 0xda, 0xb7, 0x39, 0xbe, + 0x13, 0x3b, 0xfa, 0x29, 0xda, 0x9e, 0x54, 0x64, + 0x6e, 0xba, 0xd8, 0xa1, 0xcb, 0xb3, 0x36, 0xfa, + 0xcb, 0x47, 0x85, 0xe9, 0x61, 0x38, 0xbc, 0xbe, + 0xc5, 0x00, 0x38, 0x2a, 0x54, 0xf7, 0xc4, 0xb9, + 0xb3, 0xd3, 0x7b, 0xa0, 0xa0, 0xf8, 0x72, 0x7f, + 0x8c, 0x8e, 0x82, 0x0e, 0xc6, 0x1c, 0x75, 0x9d, + 0xca, 0x8e, 0x61, 0x87, 0xde, 0xad, 0x80, 0xd2, + 0xf5, 0xf9, 0x80, 0xef, 0x15, 0x75, 0xaf, 0xf5, + 0x80, 0xfb, 0xff, 0x6d, 0x1e, 0x25, 0xb7, 0x40, + 0x61, 0x6a, 0x39, 0x5a, 0x6a, 0xb5, 0x31, 0xab, + 0x97, 0x8a, 0x19, 0x89, 0x44, 0x40, 0xc0, 0xa6, + 0xb4, 0x4e, 0x30, 0x32, 0x7b, 0x13, 0xe7, 0x67, + 0xa9, 0x8b, 0x57, 0x04, 0xc2, 0x01, 0xa6, 0xf4, + 0x28, 0x99, 0xad, 0x2c, 0x76, 0xa3, 0x78, 0xc2, + 0x4a, 0xe6, 0xca, 0x5c, 0x50, 0x6a, 0xc1, 0xb0, + 0x62, 0x4b, 0x10, 0x8e, 0x7c, 0x17, 0x43, 0xb3, + 0x17, 0x66, 0x1c, 0x3e, 0x8d, 0x69, 0xf0, 0x5a, + 0x71, 0xf5, 0x97, 0xdc, 0xd1, 0x45, 0xdd, 0x28, + 0xf3, 0x5d, 0xdf, 0x53, 0x7b, 0x11, 0xe5, 0xbc, + 0x4c, 0xdb, 0x1b, 0x51, 0x6b, 0xe9, 0xfb, 0x3d, + 0xc1, 0xc3, 0x2c, 0xb9, 0x71, 0xf5, 0xb6, 0xb2, + 0x13, 0x36, 0x79, 0x80, 0x53, 0xe8, 0xd3, 0xa6, + 0x0a, 0xaf, 0xfd, 0x56, 0x97, 0xf7, 0x40, 0x8e, + 0x45, 0xce, 0xf8, 0xb0, 0x9e, 0x5c, 0x33, 0x82, + 0xb0, 0x44, 0x56, 0xfc, 0x05, 0x09, 0xe9, 0x2a, + 0xac, 0x26, 0x80, 0x14, 0x1d, 0xc8, 0x3a, 0x35, + 0x4c, 0x82, 0x97, 0xfd, 0x76, 0xb7, 0xa9, 0x0a, + 0x35, 0x58, 0x79, 0x8e, 0x0f, 0x66, 0xea, 0xaf, + 0x51, 0x6c, 0x09, 0xa9, 0x6e, 0x9b, 0xcb, 0x9a, + 0x31, 0x47, 0xa0, 0x2f, 0x7c, 0x71, 0xb4, 0x4a, + 0x11, 0xaa, 0x8c, 0x66, 0xc5, 0x64, 0xe6, 0x3a, + 0x54, 0xda, 0x24, 0x6a, 0xc4, 0x41, 0x65, 0x46, + 0x82, 0xa0, 0x0a, 0x0f, 0x5f, 0xfb, 0x25, 0xd0, + 0x2c, 0x91, 0xa7, 0xee, 0xc4, 0x81, 0x07, 0x86, + 0x75, 0x5e, 0x33, 0x69, 0x97, 0xe4, 0x2c, 0xa8, + 0x9d, 0x9f, 0x0b, 0x6a, 0xbe, 0xad, 0x98, 0xda, + 0x6d, 0x94, 0x41, 0xda, 0x2c, 0x1e, 0x89, 0xc4, + 0xc2, 0xaf, 0x1e, 0x00, 0x05, 0x0b, 0x83, 0x60, + 0xbd, 0x43, 0xea, 0x15, 0x23, 0x7f, 0xb9, 0xac, + 0xee, 0x4f, 0x2c, 0xaf, 0x2a, 0xf3, 0xdf, 0xd0, + 0xf3, 0x19, 0x31, 0xbb, 0x4a, 0x74, 0x84, 0x17, + 0x52, 0x32, 0x2c, 0x7d, 0x61, 0xe4, 0xcb, 0xeb, + 0x80, 0x38, 0x15, 0x52, 0xcb, 0x6f, 0xea, 0xe5, + 0x73, 0x9c, 0xd9, 0x24, 0x69, 0xc6, 0x95, 0x32, + 0x21, 0xc8, 0x11, 0xe4, 0xdc, 0x36, 0xd7, 0x93, + 0x38, 0x66, 0xfb, 0xb2, 0x7f, 0x3a, 0xb9, 0xaf, + 0x31, 0xdd, 0x93, 0x75, 0x78, 0x8a, 0x2c, 0x94, + 0x87, 0x1a, 0x58, 0xec, 0x9e, 0x7d, 0x4d, 0xba, + 0xe1, 0xe5, 0x4d, 0xfc, 0xbc, 0xa4, 0x2a, 0x14, + 0xef, 0xcc, 0xa7, 0xec, 0xab, 0x43, 0x09, 0x18, + 0xd3, 0xab, 0x68, 0xd1, 0x07, 0x99, 0x44, 0x47, + 0xd6, 0x83, 0x85, 0x3b, 0x30, 0xea, 0xa9, 0x6b, + 0x63, 0xea, 0xc4, 0x07, 0xfb, 0x43, 0x2f, 0xa4, + 0xaa, 0xb0, 0xab, 0x03, 0x89, 0xce, 0x3f, 0x8c, + 0x02, 0x7c, 0x86, 0x54, 0xbc, 0x88, 0xaf, 0x75, + 0xd2, 0xdc, 0x63, 0x17, 0xd3, 0x26, 0xf6, 0x96, + 0xa9, 0x3c, 0xf1, 0x61, 0x8c, 0x11, 0x18, 0xcc, + 0xd6, 0xea, 0x5b, 0xe2, 0xcd, 0xf0, 0xf1, 0xb2, + 0xe5, 0x35, 0x90, 0x1f, 0x85, 0x4c, 0x76, 0x5b, + 0x66, 0xce, 0x44, 0xa4, 0x32, 0x9f, 0xe6, 0x7b, + 0x71, 0x6e, 0x9f, 0x58, 0x15, 0x67, 0x72, 0x87, + 0x64, 0x8e, 0x3a, 0x44, 0x45, 0xd4, 0x76, 0xfa, + 0xc2, 0xf6, 0xef, 0x85, 0x05, 0x18, 0x7a, 0x9b, + 0xba, 0x41, 0x54, 0xac, 0xf0, 0xfc, 0x59, 0x12, + 0x3f, 0xdf, 0xa0, 0xe5, 0x8a, 0x65, 0xfd, 0x3a, + 0x62, 0x8d, 0x83, 0x2c, 0x03, 0xbe, 0x05, 0x76, + 0x2e, 0x53, 0x49, 0x97, 0x94, 0x33, 0xae, 0x40, + 0x81, 0x15, 0xdb, 0x6e, 0xad, 0xaa, 0xf5, 0x4b, + 0xe3, 0x98, 0x70, 0xdf, 0xe0, 0x7c, 0xcd, 0xdb, + 0x02, 0xd4, 0x7d, 0x2f, 0xc1, 0xe6, 0xb4, 0xf3, + 0xd7, 0x0d, 0x7a, 0xd9, 0x23, 0x9e, 0x87, 0x2d, + 0xce, 0x87, 0xad, 0xcc, 0x72, 0x05, 0x00, 0x29, + 0xdc, 0x73, 0x7f, 0x64, 0xc1, 0x15, 0x0e, 0xc2, + 0xdf, 0xa7, 0x5f, 0xeb, 0x41, 0xa1, 0xcd, 0xef, + 0x5c, 0x50, 0x79, 0x2a, 0x56, 0x56, 0x71, 0x8c, + 0xac, 0xc0, 0x79, 0x50, 0x69, 0xca, 0x59, 0x32, + 0x65, 0xf2, 0x54, 0xe4, 0x52, 0x38, 0x76, 0xd1, + 0x5e, 0xde, 0x26, 0x9e, 0xfb, 0x75, 0x2e, 0x11, + 0xb5, 0x10, 0xf4, 0x17, 0x73, 0xf5, 0x89, 0xc7, + 0x4f, 0x43, 0x5c, 0x8e, 0x7c, 0xb9, 0x05, 0x52, + 0x24, 0x40, 0x99, 0xfe, 0x9b, 0x85, 0x0b, 0x6c, + 0x22, 0x3e, 0x8b, 0xae, 0x86, 0xa1, 0xd2, 0x79, + 0x05, 0x68, 0x6b, 0xab, 0xe3, 0x41, 0x49, 0xed, + 0x15, 0xa1, 0x8d, 0x40, 0x2d, 0x61, 0xdf, 0x1a, + 0x59, 0xc9, 0x26, 0x8b, 0xef, 0x30, 0x4c, 0x88, + 0x4b, 0x10, 0xf8, 0x8d, 0xa6, 0x92, 0x9f, 0x4b, + 0xf3, 0xc4, 0x53, 0x0b, 0x89, 0x5d, 0x28, 0x92, + 0xcf, 0x78, 0xb2, 0xc0, 0x5d, 0xed, 0x7e, 0xfc, + 0xc0, 0x12, 0x23, 0x5f, 0x5a, 0x78, 0x86, 0x43, + 0x6e, 0x27, 0xf7, 0x5a, 0xa7, 0x6a, 0xed, 0x19, + 0x04, 0xf0, 0xb3, 0x12, 0xd1, 0xbd, 0x0e, 0x89, + 0x6e, 0xbc, 0x96, 0xa8, 0xd8, 0x49, 0x39, 0x9f, + 0x7e, 0x67, 0xf0, 0x2e, 0x3e, 0x01, 0xa9, 0xba, + 0xec, 0x8b, 0x62, 0x8e, 0xcb, 0x4a, 0x70, 0x43, + 0xc7, 0xc2, 0xc4, 0xca, 0x82, 0x03, 0x73, 0xe9, + 0x11, 0xdf, 0xcf, 0x54, 0xea, 0xc9, 0xb0, 0x95, + 0x51, 0xc0, 0x13, 0x3d, 0x92, 0x05, 0xfa, 0xf4, + 0xa9, 0x34, 0xc8, 0xce, 0x6c, 0x3d, 0x54, 0xcc, + 0xc4, 0xaf, 0xf1, 0xdc, 0x11, 0x44, 0x26, 0xa2, + 0xaf, 0xf1, 0x85, 0x75, 0x7d, 0x03, 0x61, 0x68, + 0x4e, 0x78, 0xc6, 0x92, 0x7d, 0x86, 0x7d, 0x77, + 0xdc, 0x71, 0x72, 0xdb, 0xc6, 0xae, 0xa1, 0xcb, + 0x70, 0x9a, 0x0b, 0x19, 0xbe, 0x4a, 0x6c, 0x2a, + 0xe2, 0xba, 0x6c, 0x64, 0x9a, 0x13, 0x28, 0xdf, + 0x85, 0x75, 0xe6, 0x43, 0xf6, 0x87, 0x08, 0x68, + 0x6e, 0xba, 0x6e, 0x79, 0x9f, 0x04, 0xbc, 0x23, + 0x50, 0xf6, 0x33, 0x5c, 0x1f, 0x24, 0x25, 0xbe, + 0x33, 0x47, 0x80, 0x45, 0x56, 0xa3, 0xa7, 0xd7, + 0x7a, 0xb1, 0x34, 0x0b, 0x90, 0x3c, 0x9c, 0xad, + 0x44, 0x5f, 0x9e, 0x0e, 0x9d, 0xd4, 0xbd, 0x93, + 0x5e, 0xfa, 0x3c, 0xe0, 0xb0, 0xd9, 0xed, 0xf3, + 0xd6, 0x2e, 0xff, 0x24, 0xd8, 0x71, 0x6c, 0xed, + 0xaf, 0x55, 0xeb, 0x22, 0xac, 0x93, 0x68, 0x32, + 0x05, 0x5b, 0x47, 0xdd, 0xc6, 0x4a, 0xcb, 0xc7, + 0x10, 0xe1, 0x3c, 0x92, 0x1a, 0xf3, 0x23, 0x78, + 0x2b, 0xa1, 0xd2, 0x80, 0xf4, 0x12, 0xb1, 0x20, + 0x8f, 0xff, 0x26, 0x35, 0xdd, 0xfb, 0xc7, 0x4e, + 0x78, 0xf1, 0x2d, 0x50, 0x12, 0x77, 0xa8, 0x60, + 0x7c, 0x0f, 0xf5, 0x16, 0x2f, 0x63, 0x70, 0x2a, + 0xc0, 0x96, 0x80, 0x4e, 0x0a, 0xb4, 0x93, 0x35, + 0x5d, 0x1d, 0x3f, 0x56, 0xf7, 0x2f, 0xbb, 0x90, + 0x11, 0x16, 0x8f, 0xa2, 0xec, 0x47, 0xbe, 0xac, + 0x56, 0x01, 0x26, 0x56, 0xb1, 0x8c, 0xb2, 0x10, + 0xf9, 0x1a, 0xca, 0xf5, 0xd1, 0xb7, 0x39, 0x20, + 0x63, 0xf1, 0x69, 0x20, 0x4f, 0x13, 0x12, 0x1f, + 0x5b, 0x65, 0xfc, 0x98, 0xf7, 0xc4, 0x7a, 0xbe, + 0xf7, 0x26, 0x4d, 0x2b, 0x84, 0x7b, 0x42, 0xad, + 0xd8, 0x7a, 0x0a, 0xb4, 0xd8, 0x74, 0xbf, 0xc1, + 0xf0, 0x6e, 0xb4, 0x29, 0xa3, 0xbb, 0xca, 0x46, + 0x67, 0x70, 0x6a, 0x2d, 0xce, 0x0e, 0xa2, 0x8a, + 0xa9, 0x87, 0xbf, 0x05, 0xc4, 0xc1, 0x04, 0xa3, + 0xab, 0xd4, 0x45, 0x43, 0x8c, 0xb6, 0x02, 0xb0, + 0x41, 0xc8, 0xfc, 0x44, 0x3d, 0x59, 0xaa, 0x2e, + 0x44, 0x21, 0x2a, 0x8d, 0x88, 0x9d, 0x57, 0xf4, + 0xa0, 0x02, 0x77, 0xb8, 0xa6, 0xa0, 0xe6, 0x75, + 0x5c, 0x82, 0x65, 0x3e, 0x03, 0x5c, 0x29, 0x8f, + 0x38, 0x55, 0xab, 0x33, 0x26, 0xef, 0x9f, 0x43, + 0x52, 0xfd, 0x68, 0xaf, 0x36, 0xb4, 0xbb, 0x9a, + 0x58, 0x09, 0x09, 0x1b, 0xc3, 0x65, 0x46, 0x46, + 0x1d, 0xa7, 0x94, 0x18, 0x23, 0x50, 0x2c, 0xca, + 0x2c, 0x55, 0x19, 0x97, 0x01, 0x9d, 0x93, 0x3b, + 0x63, 0x86, 0xf2, 0x03, 0x67, 0x45, 0xd2, 0x72, + 0x28, 0x52, 0x6c, 0xf4, 0xe3, 0x1c, 0xb5, 0x11, + 0x13, 0xf1, 0xeb, 0x21, 0xc7, 0xd9, 0x56, 0x82, + 0x2b, 0x82, 0x39, 0xbd, 0x69, 0x54, 0xed, 0x62, + 0xc3, 0xe2, 0xde, 0x73, 0xd4, 0x6a, 0x12, 0xae, + 0x13, 0x21, 0x7f, 0x4b, 0x5b, 0xfc, 0xbf, 0xe8, + 0x2b, 0xbe, 0x56, 0xba, 0x68, 0x8b, 0x9a, 0xb1, + 0x6e, 0xfa, 0xbf, 0x7e, 0x5a, 0x4b, 0xf1, 0xac, + 0x98, 0x65, 0x85, 0xd1, 0x93, 0x53, 0xd3, 0x7b, + 0x09, 0xdd, 0x4b, 0x10, 0x6d, 0x84, 0xb0, 0x13, + 0x65, 0xbd, 0xcf, 0x52, 0x09, 0xc4, 0x85, 0xe2, + 0x84, 0x74, 0x15, 0x65, 0xb7, 0xf7, 0x51, 0xaf, + 0x55, 0xad, 0xa4, 0xd1, 0x22, 0x54, 0x70, 0x94, + 0xa0, 0x1c, 0x90, 0x41, 0xfd, 0x99, 0xd7, 0x5a, + 0x31, 0xef, 0xaa, 0x25, 0xd0, 0x7f, 0x4f, 0xea, + 0x1d, 0x55, 0x42, 0xe5, 0x49, 0xb0, 0xd0, 0x46, + 0x62, 0x36, 0x43, 0xb2, 0x82, 0x15, 0x75, 0x50, + 0xa4, 0x72, 0xeb, 0x54, 0x27, 0x1f, 0x8a, 0xe4, + 0x7d, 0xe9, 0x66, 0xc5, 0xf1, 0x53, 0xa4, 0xd1, + 0x0c, 0xeb, 0xb8, 0xf8, 0xbc, 0xd4, 0xe2, 0xe7, + 0xe1, 0xf8, 0x4b, 0xcb, 0xa9, 0xa1, 0xaf, 0x15, + 0x83, 0xcb, 0x72, 0xd0, 0x33, 0x79, 0x00, 0x2d, + 0x9f, 0xd7, 0xf1, 0x2e, 0x1e, 0x10, 0xe4, 0x45, + 0xc0, 0x75, 0x3a, 0x39, 0xea, 0x68, 0xf7, 0x5d, + 0x1b, 0x73, 0x8f, 0xe9, 0x8e, 0x0f, 0x72, 0x47, + 0xae, 0x35, 0x0a, 0x31, 0x7a, 0x14, 0x4d, 0x4a, + 0x6f, 0x47, 0xf7, 0x7e, 0x91, 0x6e, 0x74, 0x8b, + 0x26, 0x47, 0xf9, 0xc3, 0xf9, 0xde, 0x70, 0xf5, + 0x61, 0xab, 0xa9, 0x27, 0x9f, 0x82, 0xe4, 0x9c, + 0x89, 0x91, 0x3f, 0x2e, 0x6a, 0xfd, 0xb5, 0x49, + 0xe9, 0xfd, 0x59, 0x14, 0x36, 0x49, 0x40, 0x6d, + 0x32, 0xd8, 0x85, 0x42, 0xf3, 0xa5, 0xdf, 0x0c, + 0xa8, 0x27, 0xd7, 0x54, 0xe2, 0x63, 0x2f, 0xf2, + 0x7e, 0x8b, 0x8b, 0xe7, 0xf1, 0x9a, 0x95, 0x35, + 0x43, 0xdc, 0x3a, 0xe4, 0xb6, 0xf4, 0xd0, 0xdf, + 0x9c, 0xcb, 0x94, 0xf3, 0x21, 0xa0, 0x77, 0x50, + 0xe2, 0xc6, 0xc4, 0xc6, 0x5f, 0x09, 0x64, 0x5b, + 0x92, 0x90, 0xd8, 0xe1, 0xd1, 0xed, 0x4b, 0x42, + 0xd7, 0x37, 0xaf, 0x65, 0x3d, 0x11, 0x39, 0xb6, + 0x24, 0x8a, 0x60, 0xae, 0xd6, 0x1e, 0xbf, 0x0e, + 0x0d, 0xd7, 0xdc, 0x96, 0x0e, 0x65, 0x75, 0x4e, + 0x29, 0x06, 0x9d, 0xa4, 0x51, 0x3a, 0x10, 0x63, + 0x8f, 0x17, 0x07, 0xd5, 0x8e, 0x3c, 0xf4, 0x28, + 0x00, 0x5a, 0x5b, 0x05, 0x19, 0xd8, 0xc0, 0x6c, + 0xe5, 0x15, 0xe4, 0x9c, 0x9d, 0x71, 0x9d, 0x5e, + 0x94, 0x29, 0x1a, 0xa7, 0x80, 0xfa, 0x0e, 0x33, + 0x03, 0xdd, 0xb7, 0x3e, 0x9a, 0xa9, 0x26, 0x18, + 0x37, 0xa9, 0x64, 0x08, 0x4d, 0x94, 0x5a, 0x88, + 0xca, 0x35, 0xce, 0x81, 0x02, 0xe3, 0x1f, 0x1b, + 0x89, 0x1a, 0x77, 0x85, 0xe3, 0x41, 0x6d, 0x32, + 0x42, 0x19, 0x23, 0x7d, 0xc8, 0x73, 0xee, 0x25, + 0x85, 0x0d, 0xf8, 0x31, 0x25, 0x79, 0x1b, 0x6f, + 0x79, 0x25, 0xd2, 0xd8, 0xd4, 0x23, 0xfd, 0xf7, + 0x82, 0x36, 0x6a, 0x0c, 0x46, 0x22, 0x15, 0xe9, + 0xff, 0x72, 0x41, 0x91, 0x91, 0x7d, 0x3a, 0xb7, + 0xdd, 0x65, 0x99, 0x70, 0xf6, 0x8d, 0x84, 0xf8, + 0x67, 0x15, 0x20, 0x11, 0xd6, 0xb2, 0x55, 0x7b, + 0xdb, 0x87, 0xee, 0xef, 0x55, 0x89, 0x2a, 0x59, + 0x2b, 0x07, 0x8f, 0x43, 0x8a, 0x59, 0x3c, 0x01, + 0x8b, 0x65, 0x54, 0xa1, 0x66, 0xd5, 0x38, 0xbd, + 0xc6, 0x30, 0xa9, 0xcc, 0x49, 0xb6, 0xa8, 0x1b, + 0xb8, 0xc0, 0x0e, 0xe3, 0x45, 0x28, 0xe2, 0xff, + 0x41, 0x9f, 0x7e, 0x7c, 0xd1, 0xae, 0x9e, 0x25, + 0x3f, 0x4c, 0x7c, 0x7c, 0xf4, 0xa8, 0x26, 0x4d, + 0x5c, 0xfd, 0x4b, 0x27, 0x18, 0xf9, 0x61, 0x76, + 0x48, 0xba, 0x0c, 0x6b, 0xa9, 0x4d, 0xfc, 0xf5, + 0x3b, 0x35, 0x7e, 0x2f, 0x4a, 0xa9, 0xc2, 0x9a, + 0xae, 0xab, 0x86, 0x09, 0x89, 0xc9, 0xc2, 0x40, + 0x39, 0x2c, 0x81, 0xb3, 0xb8, 0x17, 0x67, 0xc2, + 0x0d, 0x32, 0x4a, 0x3a, 0x67, 0x81, 0xd7, 0x1a, + 0x34, 0x52, 0xc5, 0xdb, 0x0a, 0xf5, 0x63, 0x39, + 0xea, 0x1f, 0xe1, 0x7c, 0xa1, 0x9e, 0xc1, 0x35, + 0xe3, 0xb1, 0x18, 0x45, 0x67, 0xf9, 0x22, 0x38, + 0x95, 0xd9, 0x34, 0x34, 0x86, 0xc6, 0x41, 0x94, + 0x15, 0xf9, 0x5b, 0x41, 0xa6, 0x87, 0x8b, 0xf8, + 0xd5, 0xe1, 0x1b, 0xe2, 0x5b, 0xf3, 0x86, 0x10, + 0xff, 0xe6, 0xae, 0x69, 0x76, 0xbc, 0x0d, 0xb4, + 0x09, 0x90, 0x0c, 0xa2, 0x65, 0x0c, 0xad, 0x74, + 0xf5, 0xd7, 0xff, 0xda, 0xc1, 0xce, 0x85, 0xbe, + 0x00, 0xa7, 0xff, 0x4d, 0x2f, 0x65, 0xd3, 0x8c, + 0x86, 0x2d, 0x05, 0xe8, 0xed, 0x3e, 0x6b, 0x8b, + 0x0f, 0x3d, 0x83, 0x8c, 0xf1, 0x1d, 0x5b, 0x96, + 0x2e, 0xb1, 0x9c, 0xc2, 0x98, 0xe1, 0x70, 0xb9, + 0xba, 0x5c, 0x8a, 0x43, 0xd6, 0x34, 0xa7, 0x2d, + 0xc9, 0x92, 0xae, 0xf2, 0xa5, 0x7b, 0x05, 0x49, + 0xa7, 0x33, 0x34, 0x86, 0xca, 0xe4, 0x96, 0x23, + 0x76, 0x5b, 0xf2, 0xc6, 0xf1, 0x51, 0x28, 0x42, + 0x7b, 0xcc, 0x76, 0x8f, 0xfa, 0xa2, 0xad, 0x31, + 0xd4, 0xd6, 0x7a, 0x6d, 0x25, 0x25, 0x54, 0xe4, + 0x3f, 0x50, 0x59, 0xe1, 0x5c, 0x05, 0xb7, 0x27, + 0x48, 0xbf, 0x07, 0xec, 0x1b, 0x13, 0xbe, 0x2b, + 0xa1, 0x57, 0x2b, 0xd5, 0xab, 0xd7, 0xd0, 0x4c, + 0x1e, 0xcb, 0x71, 0x9b, 0xc5, 0x90, 0x85, 0xd3, + 0xde, 0x59, 0xec, 0x71, 0xeb, 0x89, 0xbb, 0xd0, + 0x09, 0x50, 0xe1, 0x16, 0x3f, 0xfd, 0x1c, 0x34, + 0xc3, 0x1c, 0xa1, 0x10, 0x77, 0x53, 0x98, 0xef, + 0xf2, 0xfd, 0xa5, 0x01, 0x59, 0xc2, 0x9b, 0x26, + 0xc7, 0x42, 0xd9, 0x49, 0xda, 0x58, 0x2b, 0x6e, + 0x9f, 0x53, 0x19, 0x76, 0x7e, 0xd9, 0xc9, 0x0e, + 0x68, 0xc8, 0x7f, 0x51, 0x22, 0x42, 0xef, 0x49, + 0xa4, 0x55, 0xb6, 0x36, 0xac, 0x09, 0xc7, 0x31, + 0x88, 0x15, 0x4b, 0x2e, 0x8f, 0x3a, 0x08, 0xf7, + 0xd8, 0xf7, 0xa8, 0xc5, 0xa9, 0x33, 0xa6, 0x45, + 0xe4, 0xc4, 0x94, 0x76, 0xf3, 0x0d, 0x8f, 0x7e, + 0xc8, 0xf6, 0xbc, 0x23, 0x0a, 0xb6, 0x4c, 0xd3, + 0x6a, 0xcd, 0x36, 0xc2, 0x90, 0x5c, 0x5c, 0x3c, + 0x65, 0x7b, 0xc2, 0xd6, 0xcc, 0xe6, 0x0d, 0x87, + 0x73, 0x2e, 0x71, 0x79, 0x16, 0x06, 0x63, 0x28, + 0x09, 0x15, 0xd8, 0x89, 0x38, 0x38, 0x3d, 0xb5, + 0x42, 0x1c, 0x08, 0x24, 0xf7, 0x2a, 0xd2, 0x9d, + 0xc8, 0xca, 0xef, 0xf9, 0x27, 0xd8, 0x07, 0x86, + 0xf7, 0x43, 0x0b, 0x55, 0x15, 0x3f, 0x9f, 0x83, + 0xef, 0xdc, 0x49, 0x9d, 0x2a, 0xc1, 0x54, 0x62, + 0xbd, 0x9b, 0x66, 0x55, 0x9f, 0xb7, 0x12, 0xf3, + 0x1b, 0x4d, 0x9d, 0x2a, 0x5c, 0xed, 0x87, 0x75, + 0x87, 0x26, 0xec, 0x61, 0x2c, 0xb4, 0x0f, 0x89, + 0xb0, 0xfb, 0x2e, 0x68, 0x5d, 0x15, 0xc7, 0x8d, + 0x2e, 0xc0, 0xd9, 0xec, 0xaf, 0x4f, 0xd2, 0x25, + 0x29, 0xe8, 0xd2, 0x26, 0x2b, 0x67, 0xe9, 0xfc, + 0x2b, 0xa8, 0x67, 0x96, 0x12, 0x1f, 0x5b, 0x96, + 0xc6, 0x14, 0x53, 0xaf, 0x44, 0xea, 0xd6, 0xe2, + 0x94, 0x98, 0xe4, 0x12, 0x93, 0x4c, 0x92, 0xe0, + 0x18, 0xa5, 0x8d, 0x2d, 0xe4, 0x71, 0x3c, 0x47, + 0x4c, 0xf7, 0xe6, 0x47, 0x9e, 0xc0, 0x68, 0xdf, + 0xd4, 0xf5, 0x5a, 0x74, 0xb1, 0x2b, 0x29, 0x03, + 0x19, 0x07, 0xaf, 0x90, 0x62, 0x5c, 0x68, 0x98, + 0x48, 0x16, 0x11, 0x02, 0x9d, 0xee, 0xb4, 0x9b, + 0xe5, 0x42, 0x7f, 0x08, 0xfd, 0x16, 0x32, 0x0b, + 0xd0, 0xb3, 0xfa, 0x2b, 0xb7, 0x99, 0xf9, 0x29, + 0xcd, 0x20, 0x45, 0x9f, 0xb3, 0x1a, 0x5d, 0xa2, + 0xaf, 0x4d, 0xe0, 0xbd, 0x42, 0x0d, 0xbc, 0x74, + 0x99, 0x9c, 0x8e, 0x53, 0x1a, 0xb4, 0x3e, 0xbd, + 0xa2, 0x9a, 0x2d, 0xf7, 0xf8, 0x39, 0x0f, 0x67, + 0x63, 0xfc, 0x6b, 0xc0, 0xaf, 0xb3, 0x4b, 0x4f, + 0x55, 0xc4, 0xcf, 0xa7, 0xc8, 0x04, 0x11, 0x3e, + 0x14, 0x32, 0xbb, 0x1b, 0x38, 0x77, 0xd6, 0x7f, + 0x54, 0x4c, 0xdf, 0x75, 0xf3, 0x07, 0x2d, 0x33, + 0x9b, 0xa8, 0x20, 0xe1, 0x7b, 0x12, 0xb5, 0xf3, + 0xef, 0x2f, 0xce, 0x72, 0xe5, 0x24, 0x60, 0xc1, + 0x30, 0xe2, 0xab, 0xa1, 0x8e, 0x11, 0x09, 0xa8, + 0x21, 0x33, 0x44, 0xfe, 0x7f, 0x35, 0x32, 0x93, + 0x39, 0xa7, 0xad, 0x8b, 0x79, 0x06, 0xb2, 0xcb, + 0x4e, 0xa9, 0x5f, 0xc7, 0xba, 0x74, 0x29, 0xec, + 0x93, 0xa0, 0x4e, 0x54, 0x93, 0xc0, 0xbc, 0x55, + 0x64, 0xf0, 0x48, 0xe5, 0x57, 0x99, 0xee, 0x75, + 0xd6, 0x79, 0x0f, 0x66, 0xb7, 0xc6, 0x57, 0x76, + 0xf7, 0xb7, 0xf3, 0x9c, 0xc5, 0x60, 0xe8, 0x7f, + 0x83, 0x76, 0xd6, 0x0e, 0xaa, 0xe6, 0x90, 0x39, + 0x1d, 0xa6, 0x32, 0x6a, 0x34, 0xe3, 0x55, 0xf8, + 0x58, 0xa0, 0x58, 0x7d, 0x33, 0xe0, 0x22, 0x39, + 0x44, 0x64, 0x87, 0x86, 0x5a, 0x2f, 0xa7, 0x7e, + 0x0f, 0x38, 0xea, 0xb0, 0x30, 0xcc, 0x61, 0xa5, + 0x6a, 0x32, 0xae, 0x1e, 0xf7, 0xe9, 0xd0, 0xa9, + 0x0c, 0x32, 0x4b, 0xb5, 0x49, 0x28, 0xab, 0x85, + 0x2f, 0x8e, 0x01, 0x36, 0x38, 0x52, 0xd0, 0xba, + 0xd6, 0x02, 0x78, 0xf8, 0x0e, 0x3e, 0x9c, 0x8b, + 0x6b, 0x45, 0x99, 0x3f, 0x5c, 0xfe, 0x58, 0xf1, + 0x5c, 0x94, 0x04, 0xe1, 0xf5, 0x18, 0x6d, 0x51, + 0xb2, 0x5d, 0x18, 0x20, 0xb6, 0xc2, 0x9a, 0x42, + 0x1d, 0xb3, 0xab, 0x3c, 0xb6, 0x3a, 0x13, 0x03, + 0xb2, 0x46, 0x82, 0x4f, 0xfc, 0x64, 0xbc, 0x4f, + 0xca, 0xfa, 0x9c, 0xc0, 0xd5, 0xa7, 0xbd, 0x11, + 0xb7, 0xe4, 0x5a, 0xf6, 0x6f, 0x4d, 0x4d, 0x54, + 0xea, 0xa4, 0x98, 0x66, 0xd4, 0x22, 0x3b, 0xd3, + 0x8f, 0x34, 0x47, 0xd9, 0x7c, 0xf4, 0x72, 0x3b, + 0x4d, 0x02, 0x77, 0xf6, 0xd6, 0xdd, 0x08, 0x0a, + 0x81, 0xe1, 0x86, 0x89, 0x3e, 0x56, 0x10, 0x3c, + 0xba, 0xd7, 0x81, 0x8c, 0x08, 0xbc, 0x8b, 0xe2, + 0x53, 0xec, 0xa7, 0x89, 0xee, 0xc8, 0x56, 0xb5, + 0x36, 0x2c, 0xb2, 0x03, 0xba, 0x99, 0xdd, 0x7c, + 0x48, 0xa0, 0xb0, 0xbc, 0x91, 0x33, 0xe9, 0xa8, + 0xcb, 0xcd, 0xcf, 0x59, 0x5f, 0x1f, 0x15, 0xe2, + 0x56, 0xf5, 0x4e, 0x01, 0x35, 0x27, 0x45, 0x77, + 0x47, 0xc8, 0xbc, 0xcb, 0x7e, 0x39, 0xc1, 0x97, + 0x28, 0xd3, 0x84, 0xfc, 0x2c, 0x3e, 0xc8, 0xad, + 0x9c, 0xf8, 0x8a, 0x61, 0x9c, 0x28, 0xaa, 0xc5, + 0x99, 0x20, 0x43, 0x85, 0x9d, 0xa5, 0xe2, 0x8b, + 0xb8, 0xae, 0xeb, 0xd0, 0x32, 0x0d, 0x52, 0x78, + 0x09, 0x56, 0x3f, 0xc7, 0xd8, 0x7e, 0x26, 0xfc, + 0x37, 0xfb, 0x6f, 0x04, 0xfc, 0xfa, 0x92, 0x10, + 0xac, 0xf8, 0x3e, 0x21, 0xdc, 0x8c, 0x21, 0x16, + 0x7d, 0x67, 0x6e, 0xf6, 0xcd, 0xda, 0xb6, 0x98, + 0x23, 0xab, 0x23, 0x3c, 0xb2, 0x10, 0xa0, 0x53, + 0x5a, 0x56, 0x9f, 0xc5, 0xd0, 0xff, 0xbb, 0xe4, + 0x98, 0x3c, 0x69, 0x1e, 0xdb, 0x38, 0x8f, 0x7e, + 0x0f, 0xd2, 0x98, 0x88, 0x81, 0x8b, 0x45, 0x67, + 0xea, 0x33, 0xf1, 0xeb, 0xe9, 0x97, 0x55, 0x2e, + 0xd9, 0xaa, 0xeb, 0x5a, 0xec, 0xda, 0xe1, 0x68, + 0xa8, 0x9d, 0x3c, 0x84, 0x7c, 0x05, 0x3d, 0x62, + 0x87, 0x8f, 0x03, 0x21, 0x28, 0x95, 0x0c, 0x89, + 0x25, 0x22, 0x4a, 0xb0, 0x93, 0xa9, 0x50, 0xa2, + 0x2f, 0x57, 0x6e, 0x18, 0x42, 0x19, 0x54, 0x0c, + 0x55, 0x67, 0xc6, 0x11, 0x49, 0xf4, 0x5c, 0xd2, + 0xe9, 0x3d, 0xdd, 0x8b, 0x48, 0x71, 0x21, 0x00, + 0xc3, 0x9a, 0x6c, 0x85, 0x74, 0x28, 0x83, 0x4a, + 0x1b, 0x31, 0x05, 0xe1, 0x06, 0x92, 0xe7, 0xda, + 0x85, 0x73, 0x78, 0x45, 0x20, 0x7f, 0xae, 0x13, + 0x7c, 0x33, 0x06, 0x22, 0xf4, 0x83, 0xf9, 0x35, + 0x3f, 0x6c, 0x71, 0xa8, 0x4e, 0x48, 0xbe, 0x9b, + 0xce, 0x8a, 0xba, 0xda, 0xbe, 0x28, 0x08, 0xf7, + 0xe2, 0x14, 0x8c, 0x71, 0xea, 0x72, 0xf9, 0x33, + 0xf2, 0x88, 0x3f, 0xd7, 0xbb, 0x69, 0x6c, 0x29, + 0x19, 0xdc, 0x84, 0xce, 0x1f, 0x12, 0x4f, 0xc8, + 0xaf, 0xa5, 0x04, 0xba, 0x5a, 0xab, 0xb0, 0xd9, + 0x14, 0x1f, 0x6c, 0x68, 0x98, 0x39, 0x89, 0x7a, + 0xd9, 0xd8, 0x2f, 0xdf, 0xa8, 0x47, 0x4a, 0x25, + 0xe2, 0xfb, 0x33, 0xf4, 0x59, 0x78, 0xe1, 0x68, + 0x85, 0xcf, 0xfe, 0x59, 0x20, 0xd4, 0x05, 0x1d, + 0x80, 0x99, 0xae, 0xbc, 0xca, 0xae, 0x0f, 0x2f, + 0x65, 0x43, 0x34, 0x8e, 0x7e, 0xac, 0xd3, 0x93, + 0x2f, 0xac, 0x6d, 0x14, 0x3d, 0x02, 0x07, 0x70, + 0x9d, 0xa4, 0xf3, 0x1b, 0x5c, 0x36, 0xfc, 0x01, + 0x73, 0x34, 0x85, 0x0c, 0x6c, 0xd6, 0xf1, 0xbd, + 0x3f, 0xdf, 0xee, 0xf5, 0xd9, 0xba, 0x56, 0xef, + 0xf4, 0x9b, 0x6b, 0xee, 0x9f, 0x5a, 0x78, 0x6d, + 0x32, 0x19, 0xf4, 0xf7, 0xf8, 0x4c, 0x69, 0x0b, + 0x4b, 0xbc, 0xbb, 0xb7, 0xf2, 0x85, 0xaf, 0x70, + 0x75, 0x24, 0x6c, 0x54, 0xa7, 0x0e, 0x4d, 0x1d, + 0x01, 0xbf, 0x08, 0xac, 0xcf, 0x7f, 0x2c, 0xe3, + 0x14, 0x89, 0x5e, 0x70, 0x5a, 0x99, 0x92, 0xcd, + 0x01, 0x84, 0xc8, 0xd2, 0xab, 0xe5, 0x4f, 0x58, + 0xe7, 0x0f, 0x2f, 0x0e, 0xff, 0x68, 0xea, 0xfd, + 0x15, 0xb3, 0x17, 0xe6, 0xb0, 0xe7, 0x85, 0xd8, + 0x23, 0x2e, 0x05, 0xc7, 0xc9, 0xc4, 0x46, 0x1f, + 0xe1, 0x9e, 0x49, 0x20, 0x23, 0x24, 0x4d, 0x7e, + 0x29, 0x65, 0xff, 0xf4, 0xb6, 0xfd, 0x1a, 0x85, + 0xc4, 0x16, 0xec, 0xfc, 0xea, 0x7b, 0xd6, 0x2c, + 0x43, 0xf8, 0xb7, 0xbf, 0x79, 0xc0, 0x85, 0xcd, + 0xef, 0xe1, 0x98, 0xd3, 0xa5, 0xf7, 0x90, 0x8c, + 0xe9, 0x7f, 0x80, 0x6b, 0xd2, 0xac, 0x4c, 0x30, + 0xa7, 0xc6, 0x61, 0x6c, 0xd2, 0xf9, 0x2c, 0xff, + 0x30, 0xbc, 0x22, 0x81, 0x7d, 0x93, 0x12, 0xe4, + 0x0a, 0xcd, 0xaf, 0xdd, 0xe8, 0xab, 0x0a, 0x1e, + 0x13, 0xa4, 0x27, 0xc3, 0x5f, 0xf7, 0x4b, 0xbb, + 0x37, 0x09, 0x4b, 0x91, 0x6f, 0x92, 0x4f, 0xaf, + 0x52, 0xee, 0xdf, 0xef, 0x09, 0x6f, 0xf7, 0x5c, + 0x6e, 0x12, 0x17, 0x72, 0x63, 0x57, 0xc7, 0xba, + 0x3b, 0x6b, 0x38, 0x32, 0x73, 0x1b, 0x9c, 0x80, + 0xc1, 0x7a, 0xc6, 0xcf, 0xcd, 0x35, 0xc0, 0x6b, + 0x31, 0x1a, 0x6b, 0xe9, 0xd8, 0x2c, 0x29, 0x3f, + 0x96, 0xfb, 0xb6, 0xcd, 0x13, 0x91, 0x3b, 0xc2, + 0xd2, 0xa3, 0x31, 0x8d, 0xa4, 0xcd, 0x57, 0xcd, + 0x13, 0x3d, 0x64, 0xfd, 0x06, 0xce, 0xe6, 0xdc, + 0x0c, 0x24, 0x43, 0x31, 0x40, 0x57, 0xf1, 0x72, + 0x17, 0xe3, 0x3a, 0x63, 0x6d, 0x35, 0xcf, 0x5d, + 0x97, 0x40, 0x59, 0xdd, 0xf7, 0x3c, 0x02, 0xf7, + 0x1c, 0x7e, 0x05, 0xbb, 0xa9, 0x0d, 0x01, 0xb1, + 0x8e, 0xc0, 0x30, 0xa9, 0x53, 0x24, 0xc9, 0x89, + 0x84, 0x6d, 0xaa, 0xd0, 0xcd, 0x91, 0xc2, 0x4d, + 0x91, 0xb0, 0x89, 0xe2, 0xbf, 0x83, 0x44, 0xaa, + 0x28, 0x72, 0x23, 0xa0, 0xc2, 0xad, 0xad, 0x1c, + 0xfc, 0x3f, 0x09, 0x7a, 0x0b, 0xdc, 0xc5, 0x1b, + 0x87, 0x13, 0xc6, 0x5b, 0x59, 0x8d, 0xf2, 0xc8, + 0xaf, 0xdf, 0x11, 0x95, + }, + .rlen = 4100, + }, +}; + /* * Compression stuff. */ @@ -4408,6 +7721,88 @@ static struct comp_testvec deflate_decomp_tv_template[] = { }; /* + * LZO test vectors (null-terminated strings). + */ +#define LZO_COMP_TEST_VECTORS 2 +#define LZO_DECOMP_TEST_VECTORS 2 + +static struct comp_testvec lzo_comp_tv_template[] = { + { + .inlen = 70, + .outlen = 46, + .input = "Join us now and share the software " + "Join us now and share the software ", + .output = { 0x00, 0x0d, 0x4a, 0x6f, 0x69, 0x6e, 0x20, 0x75, + 0x73, 0x20, 0x6e, 0x6f, 0x77, 0x20, 0x61, 0x6e, + 0x64, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x73, 0x6f, 0x66, 0x74, + 0x77, 0x70, 0x01, 0x01, 0x4a, 0x6f, 0x69, 0x6e, + 0x3d, 0x88, 0x00, 0x11, 0x00, 0x00 }, + }, { + .inlen = 159, + .outlen = 133, + .input = "This document describes a compression method based on the LZO " + "compression algorithm. This document defines the application of " + "the LZO algorithm used in UBIFS.", + .output = { 0x00, 0x2b, 0x54, 0x68, 0x69, 0x73, 0x20, 0x64, + 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, + 0x73, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x70, + 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, + 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x20, 0x62, + 0x61, 0x73, 0x65, 0x64, 0x20, 0x6f, 0x6e, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x4c, 0x5a, 0x4f, 0x2b, + 0x8c, 0x00, 0x0d, 0x61, 0x6c, 0x67, 0x6f, 0x72, + 0x69, 0x74, 0x68, 0x6d, 0x2e, 0x20, 0x20, 0x54, + 0x68, 0x69, 0x73, 0x2a, 0x54, 0x01, 0x02, 0x66, + 0x69, 0x6e, 0x65, 0x73, 0x94, 0x06, 0x05, 0x61, + 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x76, + 0x0a, 0x6f, 0x66, 0x88, 0x02, 0x60, 0x09, 0x27, + 0xf0, 0x00, 0x0c, 0x20, 0x75, 0x73, 0x65, 0x64, + 0x20, 0x69, 0x6e, 0x20, 0x55, 0x42, 0x49, 0x46, + 0x53, 0x2e, 0x11, 0x00, 0x00 }, + }, +}; + +static struct comp_testvec lzo_decomp_tv_template[] = { + { + .inlen = 133, + .outlen = 159, + .input = { 0x00, 0x2b, 0x54, 0x68, 0x69, 0x73, 0x20, 0x64, + 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, + 0x73, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x70, + 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, + 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x20, 0x62, + 0x61, 0x73, 0x65, 0x64, 0x20, 0x6f, 0x6e, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x4c, 0x5a, 0x4f, 0x2b, + 0x8c, 0x00, 0x0d, 0x61, 0x6c, 0x67, 0x6f, 0x72, + 0x69, 0x74, 0x68, 0x6d, 0x2e, 0x20, 0x20, 0x54, + 0x68, 0x69, 0x73, 0x2a, 0x54, 0x01, 0x02, 0x66, + 0x69, 0x6e, 0x65, 0x73, 0x94, 0x06, 0x05, 0x61, + 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x76, + 0x0a, 0x6f, 0x66, 0x88, 0x02, 0x60, 0x09, 0x27, + 0xf0, 0x00, 0x0c, 0x20, 0x75, 0x73, 0x65, 0x64, + 0x20, 0x69, 0x6e, 0x20, 0x55, 0x42, 0x49, 0x46, + 0x53, 0x2e, 0x11, 0x00, 0x00 }, + .output = "This document describes a compression method based on the LZO " + "compression algorithm. This document defines the application of " + "the LZO algorithm used in UBIFS.", + }, { + .inlen = 46, + .outlen = 70, + .input = { 0x00, 0x0d, 0x4a, 0x6f, 0x69, 0x6e, 0x20, 0x75, + 0x73, 0x20, 0x6e, 0x6f, 0x77, 0x20, 0x61, 0x6e, + 0x64, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x73, 0x6f, 0x66, 0x74, + 0x77, 0x70, 0x01, 0x01, 0x4a, 0x6f, 0x69, 0x6e, + 0x3d, 0x88, 0x00, 0x11, 0x00, 0x00 }, + .output = "Join us now and share the software " + "Join us now and share the software ", + }, +}; + +/* * Michael MIC test vectors from IEEE 802.11i */ #define MICHAEL_MIC_TEST_VECTORS 6 @@ -4812,4 +8207,20 @@ static struct cipher_speed camellia_speed_template[] = { { .klen = 0, .blen = 0, } }; +static struct cipher_speed salsa20_speed_template[] = { + { .klen = 16, .blen = 16, }, + { .klen = 16, .blen = 64, }, + { .klen = 16, .blen = 256, }, + { .klen = 16, .blen = 1024, }, + { .klen = 16, .blen = 8192, }, + { .klen = 32, .blen = 16, }, + { .klen = 32, .blen = 64, }, + { .klen = 32, .blen = 256, }, + { .klen = 32, .blen = 1024, }, + { .klen = 32, .blen = 8192, }, + + /* End marker */ + { .klen = 0, .blen = 0, } +}; + #endif /* _CRYPTO_TCRYPT_H */ diff --git a/crypto/twofish_common.c b/crypto/twofish_common.c index b4b9c0c3f4ae..0af216c75d7e 100644 --- a/crypto/twofish_common.c +++ b/crypto/twofish_common.c @@ -655,84 +655,48 @@ int twofish_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int key_len) CALC_SB256_2( i, calc_sb_tbl[j], calc_sb_tbl[k] ); } - /* Calculate whitening and round subkeys. The constants are - * indices of subkeys, preprocessed through q0 and q1. */ - CALC_K256 (w, 0, 0xA9, 0x75, 0x67, 0xF3); - CALC_K256 (w, 2, 0xB3, 0xC6, 0xE8, 0xF4); - CALC_K256 (w, 4, 0x04, 0xDB, 0xFD, 0x7B); - CALC_K256 (w, 6, 0xA3, 0xFB, 0x76, 0xC8); - CALC_K256 (k, 0, 0x9A, 0x4A, 0x92, 0xD3); - CALC_K256 (k, 2, 0x80, 0xE6, 0x78, 0x6B); - CALC_K256 (k, 4, 0xE4, 0x45, 0xDD, 0x7D); - CALC_K256 (k, 6, 0xD1, 0xE8, 0x38, 0x4B); - CALC_K256 (k, 8, 0x0D, 0xD6, 0xC6, 0x32); - CALC_K256 (k, 10, 0x35, 0xD8, 0x98, 0xFD); - CALC_K256 (k, 12, 0x18, 0x37, 0xF7, 0x71); - CALC_K256 (k, 14, 0xEC, 0xF1, 0x6C, 0xE1); - CALC_K256 (k, 16, 0x43, 0x30, 0x75, 0x0F); - CALC_K256 (k, 18, 0x37, 0xF8, 0x26, 0x1B); - CALC_K256 (k, 20, 0xFA, 0x87, 0x13, 0xFA); - CALC_K256 (k, 22, 0x94, 0x06, 0x48, 0x3F); - CALC_K256 (k, 24, 0xF2, 0x5E, 0xD0, 0xBA); - CALC_K256 (k, 26, 0x8B, 0xAE, 0x30, 0x5B); - CALC_K256 (k, 28, 0x84, 0x8A, 0x54, 0x00); - CALC_K256 (k, 30, 0xDF, 0xBC, 0x23, 0x9D); + /* CALC_K256/CALC_K192/CALC_K loops were unrolled. + * Unrolling produced x2.5 more code (+18k on i386), + * and speeded up key setup by 7%: + * unrolled: twofish_setkey/sec: 41128 + * loop: twofish_setkey/sec: 38148 + * CALC_K256: ~100 insns each + * CALC_K192: ~90 insns + * CALC_K: ~70 insns + */ + /* Calculate whitening and round subkeys */ + for ( i = 0; i < 8; i += 2 ) { + CALC_K256 (w, i, q0[i], q1[i], q0[i+1], q1[i+1]); + } + for ( i = 0; i < 32; i += 2 ) { + CALC_K256 (k, i, q0[i+8], q1[i+8], q0[i+9], q1[i+9]); + } } else if (key_len == 24) { /* 192-bit key */ /* Compute the S-boxes. */ for ( i = j = 0, k = 1; i < 256; i++, j += 2, k += 2 ) { CALC_SB192_2( i, calc_sb_tbl[j], calc_sb_tbl[k] ); } - /* Calculate whitening and round subkeys. The constants are - * indices of subkeys, preprocessed through q0 and q1. */ - CALC_K192 (w, 0, 0xA9, 0x75, 0x67, 0xF3); - CALC_K192 (w, 2, 0xB3, 0xC6, 0xE8, 0xF4); - CALC_K192 (w, 4, 0x04, 0xDB, 0xFD, 0x7B); - CALC_K192 (w, 6, 0xA3, 0xFB, 0x76, 0xC8); - CALC_K192 (k, 0, 0x9A, 0x4A, 0x92, 0xD3); - CALC_K192 (k, 2, 0x80, 0xE6, 0x78, 0x6B); - CALC_K192 (k, 4, 0xE4, 0x45, 0xDD, 0x7D); - CALC_K192 (k, 6, 0xD1, 0xE8, 0x38, 0x4B); - CALC_K192 (k, 8, 0x0D, 0xD6, 0xC6, 0x32); - CALC_K192 (k, 10, 0x35, 0xD8, 0x98, 0xFD); - CALC_K192 (k, 12, 0x18, 0x37, 0xF7, 0x71); - CALC_K192 (k, 14, 0xEC, 0xF1, 0x6C, 0xE1); - CALC_K192 (k, 16, 0x43, 0x30, 0x75, 0x0F); - CALC_K192 (k, 18, 0x37, 0xF8, 0x26, 0x1B); - CALC_K192 (k, 20, 0xFA, 0x87, 0x13, 0xFA); - CALC_K192 (k, 22, 0x94, 0x06, 0x48, 0x3F); - CALC_K192 (k, 24, 0xF2, 0x5E, 0xD0, 0xBA); - CALC_K192 (k, 26, 0x8B, 0xAE, 0x30, 0x5B); - CALC_K192 (k, 28, 0x84, 0x8A, 0x54, 0x00); - CALC_K192 (k, 30, 0xDF, 0xBC, 0x23, 0x9D); + /* Calculate whitening and round subkeys */ + for ( i = 0; i < 8; i += 2 ) { + CALC_K192 (w, i, q0[i], q1[i], q0[i+1], q1[i+1]); + } + for ( i = 0; i < 32; i += 2 ) { + CALC_K192 (k, i, q0[i+8], q1[i+8], q0[i+9], q1[i+9]); + } } else { /* 128-bit key */ /* Compute the S-boxes. */ for ( i = j = 0, k = 1; i < 256; i++, j += 2, k += 2 ) { CALC_SB_2( i, calc_sb_tbl[j], calc_sb_tbl[k] ); } - /* Calculate whitening and round subkeys. The constants are - * indices of subkeys, preprocessed through q0 and q1. */ - CALC_K (w, 0, 0xA9, 0x75, 0x67, 0xF3); - CALC_K (w, 2, 0xB3, 0xC6, 0xE8, 0xF4); - CALC_K (w, 4, 0x04, 0xDB, 0xFD, 0x7B); - CALC_K (w, 6, 0xA3, 0xFB, 0x76, 0xC8); - CALC_K (k, 0, 0x9A, 0x4A, 0x92, 0xD3); - CALC_K (k, 2, 0x80, 0xE6, 0x78, 0x6B); - CALC_K (k, 4, 0xE4, 0x45, 0xDD, 0x7D); - CALC_K (k, 6, 0xD1, 0xE8, 0x38, 0x4B); - CALC_K (k, 8, 0x0D, 0xD6, 0xC6, 0x32); - CALC_K (k, 10, 0x35, 0xD8, 0x98, 0xFD); - CALC_K (k, 12, 0x18, 0x37, 0xF7, 0x71); - CALC_K (k, 14, 0xEC, 0xF1, 0x6C, 0xE1); - CALC_K (k, 16, 0x43, 0x30, 0x75, 0x0F); - CALC_K (k, 18, 0x37, 0xF8, 0x26, 0x1B); - CALC_K (k, 20, 0xFA, 0x87, 0x13, 0xFA); - CALC_K (k, 22, 0x94, 0x06, 0x48, 0x3F); - CALC_K (k, 24, 0xF2, 0x5E, 0xD0, 0xBA); - CALC_K (k, 26, 0x8B, 0xAE, 0x30, 0x5B); - CALC_K (k, 28, 0x84, 0x8A, 0x54, 0x00); - CALC_K (k, 30, 0xDF, 0xBC, 0x23, 0x9D); + /* Calculate whitening and round subkeys */ + for ( i = 0; i < 8; i += 2 ) { + CALC_K (w, i, q0[i], q1[i], q0[i+1], q1[i+1]); + } + for ( i = 0; i < 32; i += 2 ) { + CALC_K (k, i, q0[i+8], q1[i+8], q0[i+9], q1[i+9]); + } } return 0; diff --git a/crypto/xcbc.c b/crypto/xcbc.c index ac68f3b62fde..a82959df678c 100644 --- a/crypto/xcbc.c +++ b/crypto/xcbc.c @@ -19,6 +19,7 @@ * Kazunori Miyazawa <miyazawa@linux-ipv6.org> */ +#include <crypto/scatterwalk.h> #include <linux/crypto.h> #include <linux/err.h> #include <linux/hardirq.h> @@ -27,7 +28,6 @@ #include <linux/rtnetlink.h> #include <linux/slab.h> #include <linux/scatterlist.h> -#include "internal.h" static u_int32_t ks[12] = {0x01010101, 0x01010101, 0x01010101, 0x01010101, 0x02020202, 0x02020202, 0x02020202, 0x02020202, @@ -307,7 +307,8 @@ static struct crypto_instance *xcbc_alloc(struct rtattr **tb) case 16: break; default: - return ERR_PTR(PTR_ERR(alg)); + inst = ERR_PTR(-EINVAL); + goto out_put_alg; } inst = crypto_alloc_instance("xcbc", alg); @@ -320,10 +321,7 @@ static struct crypto_instance *xcbc_alloc(struct rtattr **tb) inst->alg.cra_alignmask = alg->cra_alignmask; inst->alg.cra_type = &crypto_hash_type; - inst->alg.cra_hash.digestsize = - (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) == - CRYPTO_ALG_TYPE_HASH ? alg->cra_hash.digestsize : - alg->cra_blocksize; + inst->alg.cra_hash.digestsize = alg->cra_blocksize; inst->alg.cra_ctxsize = sizeof(struct crypto_xcbc_ctx) + ALIGN(inst->alg.cra_blocksize * 3, sizeof(void *)); inst->alg.cra_init = xcbc_init_tfm; diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index f4487c38d9f2..1b4cf984b081 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 c9f526e55392..5400ea173f6f 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 edee2806e37b..5ffe0ea18967 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 b39ea3f59c9b..63e09c015ca0 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 7370d7cf5988..d4dfb97de3b0 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 10b2fb6c9ce6..c0444146c09a 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 9a19b071c573..f484495b2ad1 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 @@ out_put: } /** - * 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 a863bb091e11..59cf35894cfc 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 @@ out: 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 2683eac30c68..edf3bbeb8d6a 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 @@ error: 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 @@ out: 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 40545071e3c9..c5885f5ce0ac 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 7ac474db88c5..a5cde94bb982 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 @@ done: 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 eb11475293ed..a35f04121a00 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 90c862932169..113815556809 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 7080b413ddc9..6428cba3aadd 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 37138154f9e8..7bd9b6a5b01f 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 7868707c7eda..7ae413fdd5fc 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 000000000000..103be9cacb05 --- /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 88eeed72b5d6..e59861f18ce5 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 fb5609241482..efaf282c438c 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 44504e6618fb..06a86fe6a78d 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 691ffb64cc37..200ed5fafd50 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 379da4e958e0..6f0dfca8ebdd 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 56e8eaaac012..000000000000 --- 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 ac7ff6d0c6e5..2f79c55acdcc 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 @@ aux_driver: } /* 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 ad00b3d94711..826d12381e21 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 39e563ea0878..d5480e34cb22 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 b4c0888aedc3..ba9b17e507e0 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -375,14 +375,17 @@ harderror: 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 d89e7d32a3b6..ab86e23ddc69 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 b91accf12656..76096cad798f 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 3535ef896677..e9de1712e5a0 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 2e3a0d4bc4c2..466629594776 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 07304d50e0cb..96fc01eddefe 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 8252f8668538..480fae29c9b2 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 69d8866de783..fd7559084b82 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 @@ fast_open: 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 @@ open_success: 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/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c index 556fd81fa815..c422e870dc52 100644 --- a/drivers/char/hw_random/amd-rng.c +++ b/drivers/char/hw_random/amd-rng.c @@ -28,6 +28,7 @@ #include <linux/kernel.h> #include <linux/pci.h> #include <linux/hw_random.h> +#include <linux/delay.h> #include <asm/io.h> @@ -52,11 +53,18 @@ MODULE_DEVICE_TABLE(pci, pci_tbl); static struct pci_dev *amd_pdev; -static int amd_rng_data_present(struct hwrng *rng) +static int amd_rng_data_present(struct hwrng *rng, int wait) { u32 pmbase = (u32)rng->priv; + int data, i; - return !!(inl(pmbase + 0xF4) & 1); + for (i = 0; i < 20; i++) { + data = !!(inl(pmbase + 0xF4) & 1); + if (data || !wait) + break; + udelay(10); + } + return data; } static int amd_rng_data_read(struct hwrng *rng, u32 *data) diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 26a860adcb38..0118b9817a95 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -66,11 +66,11 @@ static inline void hwrng_cleanup(struct hwrng *rng) rng->cleanup(rng); } -static inline int hwrng_data_present(struct hwrng *rng) +static inline int hwrng_data_present(struct hwrng *rng, int wait) { if (!rng->data_present) return 1; - return rng->data_present(rng); + return rng->data_present(rng, wait); } static inline int hwrng_data_read(struct hwrng *rng, u32 *data) @@ -94,8 +94,7 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf, { u32 data; ssize_t ret = 0; - int i, err = 0; - int data_present; + int err = 0; int bytes_read; while (size) { @@ -107,21 +106,10 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf, err = -ENODEV; goto out; } - if (filp->f_flags & O_NONBLOCK) { - data_present = hwrng_data_present(current_rng); - } else { - /* Some RNG require some time between data_reads to gather - * new entropy. Poll it. - */ - for (i = 0; i < 20; i++) { - data_present = hwrng_data_present(current_rng); - if (data_present) - break; - udelay(10); - } - } + bytes_read = 0; - if (data_present) + if (hwrng_data_present(current_rng, + !(filp->f_flags & O_NONBLOCK))) bytes_read = hwrng_data_read(current_rng, &data); mutex_unlock(&rng_mutex); diff --git a/drivers/char/hw_random/geode-rng.c b/drivers/char/hw_random/geode-rng.c index 8e8658dcd2e3..fed4ef5569f5 100644 --- a/drivers/char/hw_random/geode-rng.c +++ b/drivers/char/hw_random/geode-rng.c @@ -28,6 +28,7 @@ #include <linux/kernel.h> #include <linux/pci.h> #include <linux/hw_random.h> +#include <linux/delay.h> #include <asm/io.h> @@ -61,11 +62,18 @@ static int geode_rng_data_read(struct hwrng *rng, u32 *data) return 4; } -static int geode_rng_data_present(struct hwrng *rng) +static int geode_rng_data_present(struct hwrng *rng, int wait) { void __iomem *mem = (void __iomem *)rng->priv; + int data, i; - return !!(readl(mem + GEODE_RNG_STATUS_REG)); + for (i = 0; i < 20; i++) { + data = !!(readl(mem + GEODE_RNG_STATUS_REG)); + if (data || !wait) + break; + udelay(10); + } + return data; } diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c index 753f46052b87..5cc651ef75eb 100644 --- a/drivers/char/hw_random/intel-rng.c +++ b/drivers/char/hw_random/intel-rng.c @@ -29,6 +29,7 @@ #include <linux/module.h> #include <linux/pci.h> #include <linux/stop_machine.h> +#include <linux/delay.h> #include <asm/io.h> @@ -162,11 +163,19 @@ static inline u8 hwstatus_set(void __iomem *mem, return hwstatus_get(mem); } -static int intel_rng_data_present(struct hwrng *rng) +static int intel_rng_data_present(struct hwrng *rng, int wait) { void __iomem *mem = (void __iomem *)rng->priv; - - return !!(readb(mem + INTEL_RNG_STATUS) & INTEL_RNG_DATA_PRESENT); + int data, i; + + for (i = 0; i < 20; i++) { + data = !!(readb(mem + INTEL_RNG_STATUS) & + INTEL_RNG_DATA_PRESENT); + if (data || !wait) + break; + udelay(10); + } + return data; } static int intel_rng_data_read(struct hwrng *rng, u32 *data) diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c index 3f35a1c562b1..7e319951fa41 100644 --- a/drivers/char/hw_random/omap-rng.c +++ b/drivers/char/hw_random/omap-rng.c @@ -29,6 +29,7 @@ #include <linux/err.h> #include <linux/platform_device.h> #include <linux/hw_random.h> +#include <linux/delay.h> #include <asm/io.h> @@ -65,9 +66,17 @@ static void omap_rng_write_reg(int reg, u32 val) } /* REVISIT: Does the status bit really work on 16xx? */ -static int omap_rng_data_present(struct hwrng *rng) +static int omap_rng_data_present(struct hwrng *rng, int wait) { - return omap_rng_read_reg(RNG_STAT_REG) ? 0 : 1; + int data, i; + + for (i = 0; i < 20; i++) { + data = omap_rng_read_reg(RNG_STAT_REG) ? 0 : 1; + if (data || !wait) + break; + udelay(10); + } + return data; } static int omap_rng_data_read(struct hwrng *rng, u32 *data) diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c index fa6040b6c8f2..e2ea210cfa5f 100644 --- a/drivers/char/hw_random/pasemi-rng.c +++ b/drivers/char/hw_random/pasemi-rng.c @@ -23,6 +23,7 @@ #include <linux/kernel.h> #include <linux/platform_device.h> #include <linux/hw_random.h> +#include <linux/delay.h> #include <asm/of_platform.h> #include <asm/io.h> @@ -41,12 +42,19 @@ #define MODULE_NAME "pasemi_rng" -static int pasemi_rng_data_present(struct hwrng *rng) +static int pasemi_rng_data_present(struct hwrng *rng, int wait) { void __iomem *rng_regs = (void __iomem *)rng->priv; - - return (in_le32(rng_regs + SDCRNG_CTL_REG) - & SDCRNG_CTL_FVLD_M) ? 1 : 0; + int data, i; + + for (i = 0; i < 20; i++) { + data = (in_le32(rng_regs + SDCRNG_CTL_REG) + & SDCRNG_CTL_FVLD_M) ? 1 : 0; + if (data || !wait) + break; + udelay(10); + } + return data; } static int pasemi_rng_data_read(struct hwrng *rng, u32 *data) diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c index ec435cb25c4f..868e39fd42e4 100644 --- a/drivers/char/hw_random/via-rng.c +++ b/drivers/char/hw_random/via-rng.c @@ -27,6 +27,7 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/hw_random.h> +#include <linux/delay.h> #include <asm/io.h> #include <asm/msr.h> #include <asm/cpufeature.h> @@ -77,10 +78,11 @@ static inline u32 xstore(u32 *addr, u32 edx_in) return eax_out; } -static int via_rng_data_present(struct hwrng *rng) +static int via_rng_data_present(struct hwrng *rng, int wait) { u32 bytes_out; u32 *via_rng_datum = (u32 *)(&rng->priv); + int i; /* We choose the recommended 1-byte-per-instruction RNG rate, * for greater randomness at the expense of speed. Larger @@ -95,12 +97,15 @@ static int via_rng_data_present(struct hwrng *rng) * completes. */ - *via_rng_datum = 0; /* paranoia, not really necessary */ - bytes_out = xstore(via_rng_datum, VIA_RNG_CHUNK_1); - bytes_out &= VIA_XSTORE_CNT_MASK; - if (bytes_out == 0) - return 0; - return 1; + for (i = 0; i < 20; i++) { + *via_rng_datum = 0; /* paranoia, not really necessary */ + bytes_out = xstore(via_rng_datum, VIA_RNG_CHUNK_1); + bytes_out &= VIA_XSTORE_CNT_MASK; + if (bytes_out || !wait) + break; + udelay(10); + } + return bytes_out ? 1 : 0; } static int via_rng_data_read(struct hwrng *rng, u32 *data) diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c new file mode 100644 index 000000000000..6076e662886a --- /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 79581fab82d6..5efd5550f4ca 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 @@ err_out_unregister: 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 0f3515e77d4b..088ea74edd34 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/crypto/Kconfig b/drivers/crypto/Kconfig index ddd3a259cea1..74bd599dfb0c 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -83,4 +83,15 @@ config ZCRYPT_MONOLITHIC that contains all parts of the crypto device driver (ap bus, request router and all the card drivers). +config CRYPTO_DEV_HIFN_795X + tristate "Driver HIFN 795x crypto accelerator chips" + select CRYPTO_DES + select CRYPTO_ALGAPI + select CRYPTO_BLKCIPHER + depends on PCI + help + This option allows you to have support for HIFN 795x crypto adapters. + + + endif # CRYPTO_HW diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index d070030f7d7e..c0327f0dadc5 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o +obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c index 711e246e1ef0..4801162919d9 100644 --- a/drivers/crypto/geode-aes.c +++ b/drivers/crypto/geode-aes.c @@ -13,44 +13,13 @@ #include <linux/crypto.h> #include <linux/spinlock.h> #include <crypto/algapi.h> +#include <crypto/aes.h> #include <asm/io.h> #include <asm/delay.h> #include "geode-aes.h" -/* Register definitions */ - -#define AES_CTRLA_REG 0x0000 - -#define AES_CTRL_START 0x01 -#define AES_CTRL_DECRYPT 0x00 -#define AES_CTRL_ENCRYPT 0x02 -#define AES_CTRL_WRKEY 0x04 -#define AES_CTRL_DCA 0x08 -#define AES_CTRL_SCA 0x10 -#define AES_CTRL_CBC 0x20 - -#define AES_INTR_REG 0x0008 - -#define AES_INTRA_PENDING (1 << 16) -#define AES_INTRB_PENDING (1 << 17) - -#define AES_INTR_PENDING (AES_INTRA_PENDING | AES_INTRB_PENDING) -#define AES_INTR_MASK 0x07 - -#define AES_SOURCEA_REG 0x0010 -#define AES_DSTA_REG 0x0014 -#define AES_LENA_REG 0x0018 -#define AES_WRITEKEY0_REG 0x0030 -#define AES_WRITEIV0_REG 0x0040 - -/* A very large counter that is used to gracefully bail out of an - * operation in case of trouble - */ - -#define AES_OP_TIMEOUT 0x50000 - /* Static structures */ static void __iomem * _iobase; @@ -87,9 +56,10 @@ do_crypt(void *src, void *dst, int len, u32 flags) /* Start the operation */ iowrite32(AES_CTRL_START | flags, _iobase + AES_CTRLA_REG); - do + do { status = ioread32(_iobase + AES_INTR_REG); - while(!(status & AES_INTRA_PENDING) && --counter); + cpu_relax(); + } while(!(status & AES_INTRA_PENDING) && --counter); /* Clear the event */ iowrite32((status & 0xFF) | AES_INTRA_PENDING, _iobase + AES_INTR_REG); @@ -101,6 +71,7 @@ geode_aes_crypt(struct geode_aes_op *op) { u32 flags = 0; unsigned long iflags; + int ret; if (op->len == 0) return 0; @@ -129,7 +100,8 @@ geode_aes_crypt(struct geode_aes_op *op) _writefield(AES_WRITEKEY0_REG, op->key); } - do_crypt(op->src, op->dst, op->len, flags); + ret = do_crypt(op->src, op->dst, op->len, flags); + BUG_ON(ret); if (op->mode == AES_MODE_CBC) _readfield(AES_WRITEIV0_REG, op->iv); @@ -141,18 +113,103 @@ geode_aes_crypt(struct geode_aes_op *op) /* CRYPTO-API Functions */ -static int -geode_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int len) +static int geode_setkey_cip(struct crypto_tfm *tfm, const u8 *key, + unsigned int len) { struct geode_aes_op *op = crypto_tfm_ctx(tfm); + unsigned int ret; - if (len != AES_KEY_LENGTH) { + op->keylen = len; + + if (len == AES_KEYSIZE_128) { + memcpy(op->key, key, len); + return 0; + } + + if (len != AES_KEYSIZE_192 && len != AES_KEYSIZE_256) { + /* not supported at all */ tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; return -EINVAL; } - memcpy(op->key, key, len); - return 0; + /* + * The requested key size is not supported by HW, do a fallback + */ + op->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK; + op->fallback.blk->base.crt_flags |= (tfm->crt_flags & CRYPTO_TFM_REQ_MASK); + + ret = crypto_cipher_setkey(op->fallback.cip, key, len); + if (ret) { + tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; + tfm->crt_flags |= (op->fallback.blk->base.crt_flags & CRYPTO_TFM_RES_MASK); + } + return ret; +} + +static int geode_setkey_blk(struct crypto_tfm *tfm, const u8 *key, + unsigned int len) +{ + struct geode_aes_op *op = crypto_tfm_ctx(tfm); + unsigned int ret; + + op->keylen = len; + + if (len == AES_KEYSIZE_128) { + memcpy(op->key, key, len); + return 0; + } + + if (len != AES_KEYSIZE_192 && len != AES_KEYSIZE_256) { + /* not supported at all */ + tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + /* + * The requested key size is not supported by HW, do a fallback + */ + op->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK; + op->fallback.blk->base.crt_flags |= (tfm->crt_flags & CRYPTO_TFM_REQ_MASK); + + ret = crypto_blkcipher_setkey(op->fallback.blk, key, len); + if (ret) { + tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; + tfm->crt_flags |= (op->fallback.blk->base.crt_flags & CRYPTO_TFM_RES_MASK); + } + return ret; +} + +static int fallback_blk_dec(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + unsigned int ret; + struct crypto_blkcipher *tfm; + struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm); + + tfm = desc->tfm; + desc->tfm = op->fallback.blk; + + ret = crypto_blkcipher_decrypt_iv(desc, dst, src, nbytes); + + desc->tfm = tfm; + return ret; +} +static int fallback_blk_enc(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + unsigned int ret; + struct crypto_blkcipher *tfm; + struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm); + + tfm = desc->tfm; + desc->tfm = op->fallback.blk; + + ret = crypto_blkcipher_encrypt_iv(desc, dst, src, nbytes); + + desc->tfm = tfm; + return ret; } static void @@ -160,8 +217,10 @@ geode_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { struct geode_aes_op *op = crypto_tfm_ctx(tfm); - if ((out == NULL) || (in == NULL)) + if (unlikely(op->keylen != AES_KEYSIZE_128)) { + crypto_cipher_encrypt_one(op->fallback.cip, out, in); return; + } op->src = (void *) in; op->dst = (void *) out; @@ -179,8 +238,10 @@ geode_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { struct geode_aes_op *op = crypto_tfm_ctx(tfm); - if ((out == NULL) || (in == NULL)) + if (unlikely(op->keylen != AES_KEYSIZE_128)) { + crypto_cipher_decrypt_one(op->fallback.cip, out, in); return; + } op->src = (void *) in; op->dst = (void *) out; @@ -192,24 +253,50 @@ geode_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) geode_aes_crypt(op); } +static int fallback_init_cip(struct crypto_tfm *tfm) +{ + const char *name = tfm->__crt_alg->cra_name; + struct geode_aes_op *op = crypto_tfm_ctx(tfm); + + op->fallback.cip = crypto_alloc_cipher(name, 0, + CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); + + if (IS_ERR(op->fallback.cip)) { + printk(KERN_ERR "Error allocating fallback algo %s\n", name); + return PTR_ERR(op->fallback.blk); + } + + return 0; +} + +static void fallback_exit_cip(struct crypto_tfm *tfm) +{ + struct geode_aes_op *op = crypto_tfm_ctx(tfm); + + crypto_free_cipher(op->fallback.cip); + op->fallback.cip = NULL; +} static struct crypto_alg geode_alg = { - .cra_name = "aes", - .cra_driver_name = "geode-aes-128", - .cra_priority = 300, - .cra_alignmask = 15, - .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_name = "aes", + .cra_driver_name = "geode-aes", + .cra_priority = 300, + .cra_alignmask = 15, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER | + CRYPTO_ALG_NEED_FALLBACK, + .cra_init = fallback_init_cip, + .cra_exit = fallback_exit_cip, .cra_blocksize = AES_MIN_BLOCK_SIZE, .cra_ctxsize = sizeof(struct geode_aes_op), - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(geode_alg.cra_list), - .cra_u = { - .cipher = { - .cia_min_keysize = AES_KEY_LENGTH, - .cia_max_keysize = AES_KEY_LENGTH, - .cia_setkey = geode_setkey, - .cia_encrypt = geode_encrypt, - .cia_decrypt = geode_decrypt + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(geode_alg.cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = AES_MIN_KEY_SIZE, + .cia_max_keysize = AES_MAX_KEY_SIZE, + .cia_setkey = geode_setkey_cip, + .cia_encrypt = geode_encrypt, + .cia_decrypt = geode_decrypt } } }; @@ -223,8 +310,12 @@ geode_cbc_decrypt(struct blkcipher_desc *desc, struct blkcipher_walk walk; int err, ret; + if (unlikely(op->keylen != AES_KEYSIZE_128)) + return fallback_blk_dec(desc, dst, src, nbytes); + blkcipher_walk_init(&walk, dst, src, nbytes); err = blkcipher_walk_virt(desc, &walk); + op->iv = walk.iv; while((nbytes = walk.nbytes)) { op->src = walk.src.virt.addr, @@ -233,13 +324,9 @@ geode_cbc_decrypt(struct blkcipher_desc *desc, op->len = nbytes - (nbytes % AES_MIN_BLOCK_SIZE); op->dir = AES_DIR_DECRYPT; - memcpy(op->iv, walk.iv, AES_IV_LENGTH); - ret = geode_aes_crypt(op); - memcpy(walk.iv, op->iv, AES_IV_LENGTH); nbytes -= ret; - err = blkcipher_walk_done(desc, &walk, nbytes); } @@ -255,8 +342,12 @@ geode_cbc_encrypt(struct blkcipher_desc *desc, struct blkcipher_walk walk; int err, ret; + if (unlikely(op->keylen != AES_KEYSIZE_128)) + return fallback_blk_enc(desc, dst, src, nbytes); + blkcipher_walk_init(&walk, dst, src, nbytes); err = blkcipher_walk_virt(desc, &walk); + op->iv = walk.iv; while((nbytes = walk.nbytes)) { op->src = walk.src.virt.addr, @@ -265,8 +356,6 @@ geode_cbc_encrypt(struct blkcipher_desc *desc, op->len = nbytes - (nbytes % AES_MIN_BLOCK_SIZE); op->dir = AES_DIR_ENCRYPT; - memcpy(op->iv, walk.iv, AES_IV_LENGTH); - ret = geode_aes_crypt(op); nbytes -= ret; err = blkcipher_walk_done(desc, &walk, nbytes); @@ -275,22 +364,49 @@ geode_cbc_encrypt(struct blkcipher_desc *desc, return err; } +static int fallback_init_blk(struct crypto_tfm *tfm) +{ + const char *name = tfm->__crt_alg->cra_name; + struct geode_aes_op *op = crypto_tfm_ctx(tfm); + + op->fallback.blk = crypto_alloc_blkcipher(name, 0, + CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); + + if (IS_ERR(op->fallback.blk)) { + printk(KERN_ERR "Error allocating fallback algo %s\n", name); + return PTR_ERR(op->fallback.blk); + } + + return 0; +} + +static void fallback_exit_blk(struct crypto_tfm *tfm) +{ + struct geode_aes_op *op = crypto_tfm_ctx(tfm); + + crypto_free_blkcipher(op->fallback.blk); + op->fallback.blk = NULL; +} + static struct crypto_alg geode_cbc_alg = { .cra_name = "cbc(aes)", - .cra_driver_name = "cbc-aes-geode-128", + .cra_driver_name = "cbc-aes-geode", .cra_priority = 400, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | + CRYPTO_ALG_NEED_FALLBACK, + .cra_init = fallback_init_blk, + .cra_exit = fallback_exit_blk, .cra_blocksize = AES_MIN_BLOCK_SIZE, .cra_ctxsize = sizeof(struct geode_aes_op), .cra_alignmask = 15, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(geode_cbc_alg.cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = AES_KEY_LENGTH, - .max_keysize = AES_KEY_LENGTH, - .setkey = geode_setkey, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(geode_cbc_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = geode_setkey_blk, .encrypt = geode_cbc_encrypt, .decrypt = geode_cbc_decrypt, .ivsize = AES_IV_LENGTH, @@ -307,6 +423,9 @@ geode_ecb_decrypt(struct blkcipher_desc *desc, struct blkcipher_walk walk; int err, ret; + if (unlikely(op->keylen != AES_KEYSIZE_128)) + return fallback_blk_dec(desc, dst, src, nbytes); + blkcipher_walk_init(&walk, dst, src, nbytes); err = blkcipher_walk_virt(desc, &walk); @@ -334,6 +453,9 @@ geode_ecb_encrypt(struct blkcipher_desc *desc, struct blkcipher_walk walk; int err, ret; + if (unlikely(op->keylen != AES_KEYSIZE_128)) + return fallback_blk_enc(desc, dst, src, nbytes); + blkcipher_walk_init(&walk, dst, src, nbytes); err = blkcipher_walk_virt(desc, &walk); @@ -353,28 +475,31 @@ geode_ecb_encrypt(struct blkcipher_desc *desc, } static struct crypto_alg geode_ecb_alg = { - .cra_name = "ecb(aes)", - .cra_driver_name = "ecb-aes-geode-128", + .cra_name = "ecb(aes)", + .cra_driver_name = "ecb-aes-geode", .cra_priority = 400, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | + CRYPTO_ALG_NEED_FALLBACK, + .cra_init = fallback_init_blk, + .cra_exit = fallback_exit_blk, .cra_blocksize = AES_MIN_BLOCK_SIZE, .cra_ctxsize = sizeof(struct geode_aes_op), .cra_alignmask = 15, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(geode_ecb_alg.cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = AES_KEY_LENGTH, - .max_keysize = AES_KEY_LENGTH, - .setkey = geode_setkey, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(geode_ecb_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = geode_setkey_blk, .encrypt = geode_ecb_encrypt, .decrypt = geode_ecb_decrypt, } } }; -static void +static void __devexit geode_aes_remove(struct pci_dev *dev) { crypto_unregister_alg(&geode_alg); @@ -389,7 +514,7 @@ geode_aes_remove(struct pci_dev *dev) } -static int +static int __devinit geode_aes_probe(struct pci_dev *dev, const struct pci_device_id *id) { int ret; @@ -397,7 +522,7 @@ geode_aes_probe(struct pci_dev *dev, const struct pci_device_id *id) if ((ret = pci_enable_device(dev))) return ret; - if ((ret = pci_request_regions(dev, "geode-aes-128"))) + if ((ret = pci_request_regions(dev, "geode-aes"))) goto eenable; _iobase = pci_iomap(dev, 0, 0); @@ -472,7 +597,6 @@ geode_aes_exit(void) MODULE_AUTHOR("Advanced Micro Devices, Inc."); MODULE_DESCRIPTION("Geode LX Hardware AES driver"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("aes"); module_init(geode_aes_init); module_exit(geode_aes_exit); diff --git a/drivers/crypto/geode-aes.h b/drivers/crypto/geode-aes.h index f47968671ae7..f1855b50da48 100644 --- a/drivers/crypto/geode-aes.h +++ b/drivers/crypto/geode-aes.h @@ -9,9 +9,9 @@ #ifndef _GEODE_AES_H_ #define _GEODE_AES_H_ -#define AES_KEY_LENGTH 16 +/* driver logic flags */ #define AES_IV_LENGTH 16 - +#define AES_KEY_LENGTH 16 #define AES_MIN_BLOCK_SIZE 16 #define AES_MODE_ECB 0 @@ -22,6 +22,38 @@ #define AES_FLAGS_HIDDENKEY (1 << 0) +/* Register definitions */ + +#define AES_CTRLA_REG 0x0000 + +#define AES_CTRL_START 0x01 +#define AES_CTRL_DECRYPT 0x00 +#define AES_CTRL_ENCRYPT 0x02 +#define AES_CTRL_WRKEY 0x04 +#define AES_CTRL_DCA 0x08 +#define AES_CTRL_SCA 0x10 +#define AES_CTRL_CBC 0x20 + +#define AES_INTR_REG 0x0008 + +#define AES_INTRA_PENDING (1 << 16) +#define AES_INTRB_PENDING (1 << 17) + +#define AES_INTR_PENDING (AES_INTRA_PENDING | AES_INTRB_PENDING) +#define AES_INTR_MASK 0x07 + +#define AES_SOURCEA_REG 0x0010 +#define AES_DSTA_REG 0x0014 +#define AES_LENA_REG 0x0018 +#define AES_WRITEKEY0_REG 0x0030 +#define AES_WRITEIV0_REG 0x0040 + +/* A very large counter that is used to gracefully bail out of an + * operation in case of trouble + */ + +#define AES_OP_TIMEOUT 0x50000 + struct geode_aes_op { void *src; @@ -33,7 +65,13 @@ struct geode_aes_op { int len; u8 key[AES_KEY_LENGTH]; - u8 iv[AES_IV_LENGTH]; + u8 *iv; + + union { + struct crypto_blkcipher *blk; + struct crypto_cipher *cip; + } fallback; + u32 keylen; }; #endif diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c new file mode 100644 index 000000000000..16413e57597c --- /dev/null +++ b/drivers/crypto/hifn_795x.c @@ -0,0 +1,2838 @@ +/* + * 2007+ Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru> + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/mod_devicetable.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/mm.h> +#include <linux/dma-mapping.h> +#include <linux/scatterlist.h> +#include <linux/highmem.h> +#include <linux/interrupt.h> +#include <linux/crypto.h> +#include <linux/hw_random.h> +#include <linux/ktime.h> + +#include <crypto/algapi.h> +#include <crypto/des.h> + +#include <asm/kmap_types.h> + +#undef dprintk + +#define HIFN_TEST +//#define HIFN_DEBUG + +#ifdef HIFN_DEBUG +#define dprintk(f, a...) printk(f, ##a) +#else +#define dprintk(f, a...) do {} while (0) +#endif + +static char hifn_pll_ref[sizeof("extNNN")] = "ext"; +module_param_string(hifn_pll_ref, hifn_pll_ref, sizeof(hifn_pll_ref), 0444); +MODULE_PARM_DESC(hifn_pll_ref, + "PLL reference clock (pci[freq] or ext[freq], default ext)"); + +static atomic_t hifn_dev_number; + +#define ACRYPTO_OP_DECRYPT 0 +#define ACRYPTO_OP_ENCRYPT 1 +#define ACRYPTO_OP_HMAC 2 +#define ACRYPTO_OP_RNG 3 + +#define ACRYPTO_MODE_ECB 0 +#define ACRYPTO_MODE_CBC 1 +#define ACRYPTO_MODE_CFB 2 +#define ACRYPTO_MODE_OFB 3 + +#define ACRYPTO_TYPE_AES_128 0 +#define ACRYPTO_TYPE_AES_192 1 +#define ACRYPTO_TYPE_AES_256 2 +#define ACRYPTO_TYPE_3DES 3 +#define ACRYPTO_TYPE_DES 4 + +#define PCI_VENDOR_ID_HIFN 0x13A3 +#define PCI_DEVICE_ID_HIFN_7955 0x0020 +#define PCI_DEVICE_ID_HIFN_7956 0x001d + +/* I/O region sizes */ + +#define HIFN_BAR0_SIZE 0x1000 +#define HIFN_BAR1_SIZE 0x2000 +#define HIFN_BAR2_SIZE 0x8000 + +/* DMA registres */ + +#define HIFN_DMA_CRA 0x0C /* DMA Command Ring Address */ +#define HIFN_DMA_SDRA 0x1C /* DMA Source Data Ring Address */ +#define HIFN_DMA_RRA 0x2C /* DMA Result Ring Address */ +#define HIFN_DMA_DDRA 0x3C /* DMA Destination Data Ring Address */ +#define HIFN_DMA_STCTL 0x40 /* DMA Status and Control */ +#define HIFN_DMA_INTREN 0x44 /* DMA Interrupt Enable */ +#define HIFN_DMA_CFG1 0x48 /* DMA Configuration #1 */ +#define HIFN_DMA_CFG2 0x6C /* DMA Configuration #2 */ +#define HIFN_CHIP_ID 0x98 /* Chip ID */ + +/* + * Processing Unit Registers (offset from BASEREG0) + */ +#define HIFN_0_PUDATA 0x00 /* Processing Unit Data */ +#define HIFN_0_PUCTRL 0x04 /* Processing Unit Control */ +#define HIFN_0_PUISR 0x08 /* Processing Unit Interrupt Status */ +#define HIFN_0_PUCNFG 0x0c /* Processing Unit Configuration */ +#define HIFN_0_PUIER 0x10 /* Processing Unit Interrupt Enable */ +#define HIFN_0_PUSTAT 0x14 /* Processing Unit Status/Chip ID */ +#define HIFN_0_FIFOSTAT 0x18 /* FIFO Status */ +#define HIFN_0_FIFOCNFG 0x1c /* FIFO Configuration */ +#define HIFN_0_SPACESIZE 0x20 /* Register space size */ + +/* Processing Unit Control Register (HIFN_0_PUCTRL) */ +#define HIFN_PUCTRL_CLRSRCFIFO 0x0010 /* clear source fifo */ +#define HIFN_PUCTRL_STOP 0x0008 /* stop pu */ +#define HIFN_PUCTRL_LOCKRAM 0x0004 /* lock ram */ +#define HIFN_PUCTRL_DMAENA 0x0002 /* enable dma */ +#define HIFN_PUCTRL_RESET 0x0001 /* Reset processing unit */ + +/* Processing Unit Interrupt Status Register (HIFN_0_PUISR) */ +#define HIFN_PUISR_CMDINVAL 0x8000 /* Invalid command interrupt */ +#define HIFN_PUISR_DATAERR 0x4000 /* Data error interrupt */ +#define HIFN_PUISR_SRCFIFO 0x2000 /* Source FIFO ready interrupt */ +#define HIFN_PUISR_DSTFIFO 0x1000 /* Destination FIFO ready interrupt */ +#define HIFN_PUISR_DSTOVER 0x0200 /* Destination overrun interrupt */ +#define HIFN_PUISR_SRCCMD 0x0080 /* Source command interrupt */ +#define HIFN_PUISR_SRCCTX 0x0040 /* Source context interrupt */ +#define HIFN_PUISR_SRCDATA 0x0020 /* Source data interrupt */ +#define HIFN_PUISR_DSTDATA 0x0010 /* Destination data interrupt */ +#define HIFN_PUISR_DSTRESULT 0x0004 /* Destination result interrupt */ + +/* Processing Unit Configuration Register (HIFN_0_PUCNFG) */ +#define HIFN_PUCNFG_DRAMMASK 0xe000 /* DRAM size mask */ +#define HIFN_PUCNFG_DSZ_256K 0x0000 /* 256k dram */ +#define HIFN_PUCNFG_DSZ_512K 0x2000 /* 512k dram */ +#define HIFN_PUCNFG_DSZ_1M 0x4000 /* 1m dram */ +#define HIFN_PUCNFG_DSZ_2M 0x6000 /* 2m dram */ +#define HIFN_PUCNFG_DSZ_4M 0x8000 /* 4m dram */ +#define HIFN_PUCNFG_DSZ_8M 0xa000 /* 8m dram */ +#define HIFN_PUNCFG_DSZ_16M 0xc000 /* 16m dram */ +#define HIFN_PUCNFG_DSZ_32M 0xe000 /* 32m dram */ +#define HIFN_PUCNFG_DRAMREFRESH 0x1800 /* DRAM refresh rate mask */ +#define HIFN_PUCNFG_DRFR_512 0x0000 /* 512 divisor of ECLK */ +#define HIFN_PUCNFG_DRFR_256 0x0800 /* 256 divisor of ECLK */ +#define HIFN_PUCNFG_DRFR_128 0x1000 /* 128 divisor of ECLK */ +#define HIFN_PUCNFG_TCALLPHASES 0x0200 /* your guess is as good as mine... */ +#define HIFN_PUCNFG_TCDRVTOTEM 0x0100 /* your guess is as good as mine... */ +#define HIFN_PUCNFG_BIGENDIAN 0x0080 /* DMA big endian mode */ +#define HIFN_PUCNFG_BUS32 0x0040 /* Bus width 32bits */ +#define HIFN_PUCNFG_BUS16 0x0000 /* Bus width 16 bits */ +#define HIFN_PUCNFG_CHIPID 0x0020 /* Allow chipid from PUSTAT */ +#define HIFN_PUCNFG_DRAM 0x0010 /* Context RAM is DRAM */ +#define HIFN_PUCNFG_SRAM 0x0000 /* Context RAM is SRAM */ +#define HIFN_PUCNFG_COMPSING 0x0004 /* Enable single compression context */ +#define HIFN_PUCNFG_ENCCNFG 0x0002 /* Encryption configuration */ + +/* Processing Unit Interrupt Enable Register (HIFN_0_PUIER) */ +#define HIFN_PUIER_CMDINVAL 0x8000 /* Invalid command interrupt */ +#define HIFN_PUIER_DATAERR 0x4000 /* Data error interrupt */ +#define HIFN_PUIER_SRCFIFO 0x2000 /* Source FIFO ready interrupt */ +#define HIFN_PUIER_DSTFIFO 0x1000 /* Destination FIFO ready interrupt */ +#define HIFN_PUIER_DSTOVER 0x0200 /* Destination overrun interrupt */ +#define HIFN_PUIER_SRCCMD 0x0080 /* Source command interrupt */ +#define HIFN_PUIER_SRCCTX 0x0040 /* Source context interrupt */ +#define HIFN_PUIER_SRCDATA 0x0020 /* Source data interrupt */ +#define HIFN_PUIER_DSTDATA 0x0010 /* Destination data interrupt */ +#define HIFN_PUIER_DSTRESULT 0x0004 /* Destination result interrupt */ + +/* Processing Unit Status Register/Chip ID (HIFN_0_PUSTAT) */ +#define HIFN_PUSTAT_CMDINVAL 0x8000 /* Invalid command interrupt */ +#define HIFN_PUSTAT_DATAERR 0x4000 /* Data error interrupt */ +#define HIFN_PUSTAT_SRCFIFO 0x2000 /* Source FIFO ready interrupt */ +#define HIFN_PUSTAT_DSTFIFO 0x1000 /* Destination FIFO ready interrupt */ +#define HIFN_PUSTAT_DSTOVER 0x0200 /* Destination overrun interrupt */ +#define HIFN_PUSTAT_SRCCMD 0x0080 /* Source command interrupt */ +#define HIFN_PUSTAT_SRCCTX 0x0040 /* Source context interrupt */ +#define HIFN_PUSTAT_SRCDATA 0x0020 /* Source data interrupt */ +#define HIFN_PUSTAT_DSTDATA 0x0010 /* Destination data interrupt */ +#define HIFN_PUSTAT_DSTRESULT 0x0004 /* Destination result interrupt */ +#define HIFN_PUSTAT_CHIPREV 0x00ff /* Chip revision mask */ +#define HIFN_PUSTAT_CHIPENA 0xff00 /* Chip enabled mask */ +#define HIFN_PUSTAT_ENA_2 0x1100 /* Level 2 enabled */ +#define HIFN_PUSTAT_ENA_1 0x1000 /* Level 1 enabled */ +#define HIFN_PUSTAT_ENA_0 0x3000 /* Level 0 enabled */ +#define HIFN_PUSTAT_REV_2 0x0020 /* 7751 PT6/2 */ +#define HIFN_PUSTAT_REV_3 0x0030 /* 7751 PT6/3 */ + +/* FIFO Status Register (HIFN_0_FIFOSTAT) */ +#define HIFN_FIFOSTAT_SRC 0x7f00 /* Source FIFO available */ +#define HIFN_FIFOSTAT_DST 0x007f /* Destination FIFO available */ + +/* FIFO Configuration Register (HIFN_0_FIFOCNFG) */ +#define HIFN_FIFOCNFG_THRESHOLD 0x0400 /* must be written as 1 */ + +/* + * DMA Interface Registers (offset from BASEREG1) + */ +#define HIFN_1_DMA_CRAR 0x0c /* DMA Command Ring Address */ +#define HIFN_1_DMA_SRAR 0x1c /* DMA Source Ring Address */ +#define HIFN_1_DMA_RRAR 0x2c /* DMA Result Ring Address */ +#define HIFN_1_DMA_DRAR 0x3c /* DMA Destination Ring Address */ +#define HIFN_1_DMA_CSR 0x40 /* DMA Status and Control */ +#define HIFN_1_DMA_IER 0x44 /* DMA Interrupt Enable */ +#define HIFN_1_DMA_CNFG 0x48 /* DMA Configuration */ +#define HIFN_1_PLL 0x4c /* 795x: PLL config */ +#define HIFN_1_7811_RNGENA 0x60 /* 7811: rng enable */ +#define HIFN_1_7811_RNGCFG 0x64 /* 7811: rng config */ +#define HIFN_1_7811_RNGDAT 0x68 /* 7811: rng data */ +#define HIFN_1_7811_RNGSTS 0x6c /* 7811: rng status */ +#define HIFN_1_7811_MIPSRST 0x94 /* 7811: MIPS reset */ +#define HIFN_1_REVID 0x98 /* Revision ID */ +#define HIFN_1_UNLOCK_SECRET1 0xf4 +#define HIFN_1_UNLOCK_SECRET2 0xfc +#define HIFN_1_PUB_RESET 0x204 /* Public/RNG Reset */ +#define HIFN_1_PUB_BASE 0x300 /* Public Base Address */ +#define HIFN_1_PUB_OPLEN 0x304 /* Public Operand Length */ +#define HIFN_1_PUB_OP 0x308 /* Public Operand */ +#define HIFN_1_PUB_STATUS 0x30c /* Public Status */ +#define HIFN_1_PUB_IEN 0x310 /* Public Interrupt enable */ +#define HIFN_1_RNG_CONFIG 0x314 /* RNG config */ +#define HIFN_1_RNG_DATA 0x318 /* RNG data */ +#define HIFN_1_PUB_MEM 0x400 /* start of Public key memory */ +#define HIFN_1_PUB_MEMEND 0xbff /* end of Public key memory */ + +/* DMA Status and Control Register (HIFN_1_DMA_CSR) */ +#define HIFN_DMACSR_D_CTRLMASK 0xc0000000 /* Destinition Ring Control */ +#define HIFN_DMACSR_D_CTRL_NOP 0x00000000 /* Dest. Control: no-op */ +#define HIFN_DMACSR_D_CTRL_DIS 0x40000000 /* Dest. Control: disable */ +#define HIFN_DMACSR_D_CTRL_ENA 0x80000000 /* Dest. Control: enable */ +#define HIFN_DMACSR_D_ABORT 0x20000000 /* Destinition Ring PCIAbort */ +#define HIFN_DMACSR_D_DONE 0x10000000 /* Destinition Ring Done */ +#define HIFN_DMACSR_D_LAST 0x08000000 /* Destinition Ring Last */ +#define HIFN_DMACSR_D_WAIT 0x04000000 /* Destinition Ring Waiting */ +#define HIFN_DMACSR_D_OVER 0x02000000 /* Destinition Ring Overflow */ +#define HIFN_DMACSR_R_CTRL 0x00c00000 /* Result Ring Control */ +#define HIFN_DMACSR_R_CTRL_NOP 0x00000000 /* Result Control: no-op */ +#define HIFN_DMACSR_R_CTRL_DIS 0x00400000 /* Result Control: disable */ +#define HIFN_DMACSR_R_CTRL_ENA 0x00800000 /* Result Control: enable */ +#define HIFN_DMACSR_R_ABORT 0x00200000 /* Result Ring PCI Abort */ +#define HIFN_DMACSR_R_DONE 0x00100000 /* Result Ring Done */ +#define HIFN_DMACSR_R_LAST 0x00080000 /* Result Ring Last */ +#define HIFN_DMACSR_R_WAIT 0x00040000 /* Result Ring Waiting */ +#define HIFN_DMACSR_R_OVER 0x00020000 /* Result Ring Overflow */ +#define HIFN_DMACSR_S_CTRL 0x0000c000 /* Source Ring Control */ +#define HIFN_DMACSR_S_CTRL_NOP 0x00000000 /* Source Control: no-op */ +#define HIFN_DMACSR_S_CTRL_DIS 0x00004000 /* Source Control: disable */ +#define HIFN_DMACSR_S_CTRL_ENA 0x00008000 /* Source Control: enable */ +#define HIFN_DMACSR_S_ABORT 0x00002000 /* Source Ring PCI Abort */ +#define HIFN_DMACSR_S_DONE 0x00001000 /* Source Ring Done */ +#define HIFN_DMACSR_S_LAST 0x00000800 /* Source Ring Last */ +#define HIFN_DMACSR_S_WAIT 0x00000400 /* Source Ring Waiting */ +#define HIFN_DMACSR_ILLW 0x00000200 /* Illegal write (7811 only) */ +#define HIFN_DMACSR_ILLR 0x00000100 /* Illegal read (7811 only) */ +#define HIFN_DMACSR_C_CTRL 0x000000c0 /* Command Ring Control */ +#define HIFN_DMACSR_C_CTRL_NOP 0x00000000 /* Command Control: no-op */ +#define HIFN_DMACSR_C_CTRL_DIS 0x00000040 /* Command Control: disable */ +#define HIFN_DMACSR_C_CTRL_ENA 0x00000080 /* Command Control: enable */ +#define HIFN_DMACSR_C_ABORT 0x00000020 /* Command Ring PCI Abort */ +#define HIFN_DMACSR_C_DONE 0x00000010 /* Command Ring Done */ +#define HIFN_DMACSR_C_LAST 0x00000008 /* Command Ring Last */ +#define HIFN_DMACSR_C_WAIT 0x00000004 /* Command Ring Waiting */ +#define HIFN_DMACSR_PUBDONE 0x00000002 /* Public op done (7951 only) */ +#define HIFN_DMACSR_ENGINE 0x00000001 /* Command Ring Engine IRQ */ + +/* DMA Interrupt Enable Register (HIFN_1_DMA_IER) */ +#define HIFN_DMAIER_D_ABORT 0x20000000 /* Destination Ring PCIAbort */ +#define HIFN_DMAIER_D_DONE 0x10000000 /* Destination Ring Done */ +#define HIFN_DMAIER_D_LAST 0x08000000 /* Destination Ring Last */ +#define HIFN_DMAIER_D_WAIT 0x04000000 /* Destination Ring Waiting */ +#define HIFN_DMAIER_D_OVER 0x02000000 /* Destination Ring Overflow */ +#define HIFN_DMAIER_R_ABORT 0x00200000 /* Result Ring PCI Abort */ +#define HIFN_DMAIER_R_DONE 0x00100000 /* Result Ring Done */ +#define HIFN_DMAIER_R_LAST 0x00080000 /* Result Ring Last */ +#define HIFN_DMAIER_R_WAIT 0x00040000 /* Result Ring Waiting */ +#define HIFN_DMAIER_R_OVER 0x00020000 /* Result Ring Overflow */ +#define HIFN_DMAIER_S_ABORT 0x00002000 /* Source Ring PCI Abort */ +#define HIFN_DMAIER_S_DONE 0x00001000 /* Source Ring Done */ +#define HIFN_DMAIER_S_LAST 0x00000800 /* Source Ring Last */ +#define HIFN_DMAIER_S_WAIT 0x00000400 /* Source Ring Waiting */ +#define HIFN_DMAIER_ILLW 0x00000200 /* Illegal write (7811 only) */ +#define HIFN_DMAIER_ILLR 0x00000100 /* Illegal read (7811 only) */ +#define HIFN_DMAIER_C_ABORT 0x00000020 /* Command Ring PCI Abort */ +#define HIFN_DMAIER_C_DONE 0x00000010 /* Command Ring Done */ +#define HIFN_DMAIER_C_LAST 0x00000008 /* Command Ring Last */ +#define HIFN_DMAIER_C_WAIT 0x00000004 /* Command Ring Waiting */ +#define HIFN_DMAIER_PUBDONE 0x00000002 /* public op done (7951 only) */ +#define HIFN_DMAIER_ENGINE 0x00000001 /* Engine IRQ */ + +/* DMA Configuration Register (HIFN_1_DMA_CNFG) */ +#define HIFN_DMACNFG_BIGENDIAN 0x10000000 /* big endian mode */ +#define HIFN_DMACNFG_POLLFREQ 0x00ff0000 /* Poll frequency mask */ +#define HIFN_DMACNFG_UNLOCK 0x00000800 +#define HIFN_DMACNFG_POLLINVAL 0x00000700 /* Invalid Poll Scalar */ +#define HIFN_DMACNFG_LAST 0x00000010 /* Host control LAST bit */ +#define HIFN_DMACNFG_MODE 0x00000004 /* DMA mode */ +#define HIFN_DMACNFG_DMARESET 0x00000002 /* DMA Reset # */ +#define HIFN_DMACNFG_MSTRESET 0x00000001 /* Master Reset # */ + +/* PLL configuration register */ +#define HIFN_PLL_REF_CLK_HBI 0x00000000 /* HBI reference clock */ +#define HIFN_PLL_REF_CLK_PLL 0x00000001 /* PLL reference clock */ +#define HIFN_PLL_BP 0x00000002 /* Reference clock bypass */ +#define HIFN_PLL_PK_CLK_HBI 0x00000000 /* PK engine HBI clock */ +#define HIFN_PLL_PK_CLK_PLL 0x00000008 /* PK engine PLL clock */ +#define HIFN_PLL_PE_CLK_HBI 0x00000000 /* PE engine HBI clock */ +#define HIFN_PLL_PE_CLK_PLL 0x00000010 /* PE engine PLL clock */ +#define HIFN_PLL_RESERVED_1 0x00000400 /* Reserved bit, must be 1 */ +#define HIFN_PLL_ND_SHIFT 11 /* Clock multiplier shift */ +#define HIFN_PLL_ND_MULT_2 0x00000000 /* PLL clock multiplier 2 */ +#define HIFN_PLL_ND_MULT_4 0x00000800 /* PLL clock multiplier 4 */ +#define HIFN_PLL_ND_MULT_6 0x00001000 /* PLL clock multiplier 6 */ +#define HIFN_PLL_ND_MULT_8 0x00001800 /* PLL clock multiplier 8 */ +#define HIFN_PLL_ND_MULT_10 0x00002000 /* PLL clock multiplier 10 */ +#define HIFN_PLL_ND_MULT_12 0x00002800 /* PLL clock multiplier 12 */ +#define HIFN_PLL_IS_1_8 0x00000000 /* charge pump (mult. 1-8) */ +#define HIFN_PLL_IS_9_12 0x00010000 /* charge pump (mult. 9-12) */ + +#define HIFN_PLL_FCK_MAX 266 /* Maximum PLL frequency */ + +/* Public key reset register (HIFN_1_PUB_RESET) */ +#define HIFN_PUBRST_RESET 0x00000001 /* reset public/rng unit */ + +/* Public base address register (HIFN_1_PUB_BASE) */ +#define HIFN_PUBBASE_ADDR 0x00003fff /* base address */ + +/* Public operand length register (HIFN_1_PUB_OPLEN) */ +#define HIFN_PUBOPLEN_MOD_M 0x0000007f /* modulus length mask */ +#define HIFN_PUBOPLEN_MOD_S 0 /* modulus length shift */ +#define HIFN_PUBOPLEN_EXP_M 0x0003ff80 /* exponent length mask */ +#define HIFN_PUBOPLEN_EXP_S 7 /* exponent lenght shift */ +#define HIFN_PUBOPLEN_RED_M 0x003c0000 /* reducend length mask */ +#define HIFN_PUBOPLEN_RED_S 18 /* reducend length shift */ + +/* Public operation register (HIFN_1_PUB_OP) */ +#define HIFN_PUBOP_AOFFSET_M 0x0000007f /* A offset mask */ +#define HIFN_PUBOP_AOFFSET_S 0 /* A offset shift */ +#define HIFN_PUBOP_BOFFSET_M 0x00000f80 /* B offset mask */ +#define HIFN_PUBOP_BOFFSET_S 7 /* B offset shift */ +#define HIFN_PUBOP_MOFFSET_M 0x0003f000 /* M offset mask */ +#define HIFN_PUBOP_MOFFSET_S 12 /* M offset shift */ +#define HIFN_PUBOP_OP_MASK 0x003c0000 /* Opcode: */ +#define HIFN_PUBOP_OP_NOP 0x00000000 /* NOP */ +#define HIFN_PUBOP_OP_ADD 0x00040000 /* ADD */ +#define HIFN_PUBOP_OP_ADDC 0x00080000 /* ADD w/carry */ +#define HIFN_PUBOP_OP_SUB 0x000c0000 /* SUB */ +#define HIFN_PUBOP_OP_SUBC 0x00100000 /* SUB w/carry */ +#define HIFN_PUBOP_OP_MODADD 0x00140000 /* Modular ADD */ +#define HIFN_PUBOP_OP_MODSUB 0x00180000 /* Modular SUB */ +#define HIFN_PUBOP_OP_INCA 0x001c0000 /* INC A */ +#define HIFN_PUBOP_OP_DECA 0x00200000 /* DEC A */ +#define HIFN_PUBOP_OP_MULT 0x00240000 /* MULT */ +#define HIFN_PUBOP_OP_MODMULT 0x00280000 /* Modular MULT */ +#define HIFN_PUBOP_OP_MODRED 0x002c0000 /* Modular RED */ +#define HIFN_PUBOP_OP_MODEXP 0x00300000 /* Modular EXP */ + +/* Public status register (HIFN_1_PUB_STATUS) */ +#define HIFN_PUBSTS_DONE 0x00000001 /* operation done */ +#define HIFN_PUBSTS_CARRY 0x00000002 /* carry */ + +/* Public interrupt enable register (HIFN_1_PUB_IEN) */ +#define HIFN_PUBIEN_DONE 0x00000001 /* operation done interrupt */ + +/* Random number generator config register (HIFN_1_RNG_CONFIG) */ +#define HIFN_RNGCFG_ENA 0x00000001 /* enable rng */ + +#define HIFN_NAMESIZE 32 +#define HIFN_MAX_RESULT_ORDER 5 + +#define HIFN_D_CMD_RSIZE 24*4 +#define HIFN_D_SRC_RSIZE 80*4 +#define HIFN_D_DST_RSIZE 80*4 +#define HIFN_D_RES_RSIZE 24*4 + +#define HIFN_QUEUE_LENGTH HIFN_D_CMD_RSIZE-5 + +#define AES_MIN_KEY_SIZE 16 +#define AES_MAX_KEY_SIZE 32 + +#define HIFN_DES_KEY_LENGTH 8 +#define HIFN_3DES_KEY_LENGTH 24 +#define HIFN_MAX_CRYPT_KEY_LENGTH AES_MAX_KEY_SIZE +#define HIFN_IV_LENGTH 8 +#define HIFN_AES_IV_LENGTH 16 +#define HIFN_MAX_IV_LENGTH HIFN_AES_IV_LENGTH + +#define HIFN_MAC_KEY_LENGTH 64 +#define HIFN_MD5_LENGTH 16 +#define HIFN_SHA1_LENGTH 20 +#define HIFN_MAC_TRUNC_LENGTH 12 + +#define HIFN_MAX_COMMAND (8 + 8 + 8 + 64 + 260) +#define HIFN_MAX_RESULT (8 + 4 + 4 + 20 + 4) +#define HIFN_USED_RESULT 12 + +struct hifn_desc +{ + volatile u32 l; + volatile u32 p; +}; + +struct hifn_dma { + struct hifn_desc cmdr[HIFN_D_CMD_RSIZE+1]; + struct hifn_desc srcr[HIFN_D_SRC_RSIZE+1]; + struct hifn_desc dstr[HIFN_D_DST_RSIZE+1]; + struct hifn_desc resr[HIFN_D_RES_RSIZE+1]; + + u8 command_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_COMMAND]; + u8 result_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_RESULT]; + + u64 test_src, test_dst; + + /* + * Our current positions for insertion and removal from the descriptor + * rings. + */ + volatile int cmdi, srci, dsti, resi; + volatile int cmdu, srcu, dstu, resu; + int cmdk, srck, dstk, resk; +}; + +#define HIFN_FLAG_CMD_BUSY (1<<0) +#define HIFN_FLAG_SRC_BUSY (1<<1) +#define HIFN_FLAG_DST_BUSY (1<<2) +#define HIFN_FLAG_RES_BUSY (1<<3) +#define HIFN_FLAG_OLD_KEY (1<<4) + +#define HIFN_DEFAULT_ACTIVE_NUM 5 + +struct hifn_device +{ + char name[HIFN_NAMESIZE]; + + int irq; + + struct pci_dev *pdev; + void __iomem *bar[3]; + + unsigned long result_mem; + dma_addr_t dst; + + void *desc_virt; + dma_addr_t desc_dma; + + u32 dmareg; + + void *sa[HIFN_D_RES_RSIZE]; + + spinlock_t lock; + + void *priv; + + u32 flags; + int active, started; + struct delayed_work work; + unsigned long reset; + unsigned long success; + unsigned long prev_success; + + u8 snum; + + struct tasklet_struct tasklet; + + struct crypto_queue queue; + struct list_head alg_list; + + unsigned int pk_clk_freq; + +#if defined(CONFIG_HW_RANDOM) || defined(CONFIG_HW_RANDOM_MODULE) + unsigned int rng_wait_time; + ktime_t rngtime; + struct hwrng rng; +#endif +}; + +#define HIFN_D_LENGTH 0x0000ffff +#define HIFN_D_NOINVALID 0x01000000 +#define HIFN_D_MASKDONEIRQ 0x02000000 +#define HIFN_D_DESTOVER 0x04000000 +#define HIFN_D_OVER 0x08000000 +#define HIFN_D_LAST 0x20000000 +#define HIFN_D_JUMP 0x40000000 +#define HIFN_D_VALID 0x80000000 + +struct hifn_base_command +{ + volatile u16 masks; + volatile u16 session_num; + volatile u16 total_source_count; + volatile u16 total_dest_count; +}; + +#define HIFN_BASE_CMD_COMP 0x0100 /* enable compression engine */ +#define HIFN_BASE_CMD_PAD 0x0200 /* enable padding engine */ +#define HIFN_BASE_CMD_MAC 0x0400 /* enable MAC engine */ +#define HIFN_BASE_CMD_CRYPT 0x0800 /* enable crypt engine */ +#define HIFN_BASE_CMD_DECODE 0x2000 +#define HIFN_BASE_CMD_SRCLEN_M 0xc000 +#define HIFN_BASE_CMD_SRCLEN_S 14 +#define HIFN_BASE_CMD_DSTLEN_M 0x3000 +#define HIFN_BASE_CMD_DSTLEN_S 12 +#define HIFN_BASE_CMD_LENMASK_HI 0x30000 +#define HIFN_BASE_CMD_LENMASK_LO 0x0ffff + +/* + * Structure to help build up the command data structure. + */ +struct hifn_crypt_command +{ + volatile u16 masks; + volatile u16 header_skip; + volatile u16 source_count; + volatile u16 reserved; +}; + +#define HIFN_CRYPT_CMD_ALG_MASK 0x0003 /* algorithm: */ +#define HIFN_CRYPT_CMD_ALG_DES 0x0000 /* DES */ +#define HIFN_CRYPT_CMD_ALG_3DES 0x0001 /* 3DES */ +#define HIFN_CRYPT_CMD_ALG_RC4 0x0002 /* RC4 */ +#define HIFN_CRYPT_CMD_ALG_AES 0x0003 /* AES */ +#define HIFN_CRYPT_CMD_MODE_MASK 0x0018 /* Encrypt mode: */ +#define HIFN_CRYPT_CMD_MODE_ECB 0x0000 /* ECB */ +#define HIFN_CRYPT_CMD_MODE_CBC 0x0008 /* CBC */ +#define HIFN_CRYPT_CMD_MODE_CFB 0x0010 /* CFB */ +#define HIFN_CRYPT_CMD_MODE_OFB 0x0018 /* OFB */ +#define HIFN_CRYPT_CMD_CLR_CTX 0x0040 /* clear context */ +#define HIFN_CRYPT_CMD_KSZ_MASK 0x0600 /* AES key size: */ +#define HIFN_CRYPT_CMD_KSZ_128 0x0000 /* 128 bit */ +#define HIFN_CRYPT_CMD_KSZ_192 0x0200 /* 192 bit */ +#define HIFN_CRYPT_CMD_KSZ_256 0x0400 /* 256 bit */ +#define HIFN_CRYPT_CMD_NEW_KEY 0x0800 /* expect new key */ +#define HIFN_CRYPT_CMD_NEW_IV 0x1000 /* expect new iv */ +#define HIFN_CRYPT_CMD_SRCLEN_M 0xc000 +#define HIFN_CRYPT_CMD_SRCLEN_S 14 + +/* + * Structure to help build up the command data structure. + */ +struct hifn_mac_command +{ + volatile u16 masks; + volatile u16 header_skip; + volatile u16 source_count; + volatile u16 reserved; +}; + +#define HIFN_MAC_CMD_ALG_MASK 0x0001 +#define HIFN_MAC_CMD_ALG_SHA1 0x0000 +#define HIFN_MAC_CMD_ALG_MD5 0x0001 +#define HIFN_MAC_CMD_MODE_MASK 0x000c +#define HIFN_MAC_CMD_MODE_HMAC 0x0000 +#define HIFN_MAC_CMD_MODE_SSL_MAC 0x0004 +#define HIFN_MAC_CMD_MODE_HASH 0x0008 +#define HIFN_MAC_CMD_MODE_FULL 0x0004 +#define HIFN_MAC_CMD_TRUNC 0x0010 +#define HIFN_MAC_CMD_RESULT 0x0020 +#define HIFN_MAC_CMD_APPEND 0x0040 +#define HIFN_MAC_CMD_SRCLEN_M 0xc000 +#define HIFN_MAC_CMD_SRCLEN_S 14 + +/* + * MAC POS IPsec initiates authentication after encryption on encodes + * and before decryption on decodes. + */ +#define HIFN_MAC_CMD_POS_IPSEC 0x0200 +#define HIFN_MAC_CMD_NEW_KEY 0x0800 + +struct hifn_comp_command +{ + volatile u16 masks; + volatile u16 header_skip; + volatile u16 source_count; + volatile u16 reserved; +}; + +#define HIFN_COMP_CMD_SRCLEN_M 0xc000 +#define HIFN_COMP_CMD_SRCLEN_S 14 +#define HIFN_COMP_CMD_ONE 0x0100 /* must be one */ +#define HIFN_COMP_CMD_CLEARHIST 0x0010 /* clear history */ +#define HIFN_COMP_CMD_UPDATEHIST 0x0008 /* update history */ +#define HIFN_COMP_CMD_LZS_STRIP0 0x0004 /* LZS: strip zero */ +#define HIFN_COMP_CMD_MPPC_RESTART 0x0004 /* MPPC: restart */ +#define HIFN_COMP_CMD_ALG_MASK 0x0001 /* compression mode: */ +#define HIFN_COMP_CMD_ALG_MPPC 0x0001 /* MPPC */ +#define HIFN_COMP_CMD_ALG_LZS 0x0000 /* LZS */ + +struct hifn_base_result +{ + volatile u16 flags; + volatile u16 session; + volatile u16 src_cnt; /* 15:0 of source count */ + volatile u16 dst_cnt; /* 15:0 of dest count */ +}; + +#define HIFN_BASE_RES_DSTOVERRUN 0x0200 /* destination overrun */ +#define HIFN_BASE_RES_SRCLEN_M 0xc000 /* 17:16 of source count */ +#define HIFN_BASE_RES_SRCLEN_S 14 +#define HIFN_BASE_RES_DSTLEN_M 0x3000 /* 17:16 of dest count */ +#define HIFN_BASE_RES_DSTLEN_S 12 + +struct hifn_comp_result +{ + volatile u16 flags; + volatile u16 crc; +}; + +#define HIFN_COMP_RES_LCB_M 0xff00 /* longitudinal check byte */ +#define HIFN_COMP_RES_LCB_S 8 +#define HIFN_COMP_RES_RESTART 0x0004 /* MPPC: restart */ +#define HIFN_COMP_RES_ENDMARKER 0x0002 /* LZS: end marker seen */ +#define HIFN_COMP_RES_SRC_NOTZERO 0x0001 /* source expired */ + +struct hifn_mac_result +{ + volatile u16 flags; + volatile u16 reserved; + /* followed by 0, 6, 8, or 10 u16's of the MAC, then crypt */ +}; + +#define HIFN_MAC_RES_MISCOMPARE 0x0002 /* compare failed */ +#define HIFN_MAC_RES_SRC_NOTZERO 0x0001 /* source expired */ + +struct hifn_crypt_result +{ + volatile u16 flags; + volatile u16 reserved; +}; + +#define HIFN_CRYPT_RES_SRC_NOTZERO 0x0001 /* source expired */ + +#ifndef HIFN_POLL_FREQUENCY +#define HIFN_POLL_FREQUENCY 0x1 +#endif + +#ifndef HIFN_POLL_SCALAR +#define HIFN_POLL_SCALAR 0x0 +#endif + +#define HIFN_MAX_SEGLEN 0xffff /* maximum dma segment len */ +#define HIFN_MAX_DMALEN 0x3ffff /* maximum dma length */ + +struct hifn_crypto_alg +{ + struct list_head entry; + struct crypto_alg alg; + struct hifn_device *dev; +}; + +#define ASYNC_SCATTERLIST_CACHE 16 + +#define ASYNC_FLAGS_MISALIGNED (1<<0) + +struct ablkcipher_walk +{ + struct scatterlist cache[ASYNC_SCATTERLIST_CACHE]; + u32 flags; + int num; +}; + +struct hifn_context +{ + u8 key[HIFN_MAX_CRYPT_KEY_LENGTH], *iv; + struct hifn_device *dev; + unsigned int keysize, ivsize; + u8 op, type, mode, unused; + struct ablkcipher_walk walk; + atomic_t sg_num; +}; + +#define crypto_alg_to_hifn(a) container_of(a, struct hifn_crypto_alg, alg) + +static inline u32 hifn_read_0(struct hifn_device *dev, u32 reg) +{ + u32 ret; + + ret = readl((char *)(dev->bar[0]) + reg); + + return ret; +} + +static inline u32 hifn_read_1(struct hifn_device *dev, u32 reg) +{ + u32 ret; + + ret = readl((char *)(dev->bar[1]) + reg); + + return ret; +} + +static inline void hifn_write_0(struct hifn_device *dev, u32 reg, u32 val) +{ + writel(val, (char *)(dev->bar[0]) + reg); +} + +static inline void hifn_write_1(struct hifn_device *dev, u32 reg, u32 val) +{ + writel(val, (char *)(dev->bar[1]) + reg); +} + +static void hifn_wait_puc(struct hifn_device *dev) +{ + int i; + u32 ret; + + for (i=10000; i > 0; --i) { + ret = hifn_read_0(dev, HIFN_0_PUCTRL); + if (!(ret & HIFN_PUCTRL_RESET)) + break; + + udelay(1); + } + + if (!i) + dprintk("%s: Failed to reset PUC unit.\n", dev->name); +} + +static void hifn_reset_puc(struct hifn_device *dev) +{ + hifn_write_0(dev, HIFN_0_PUCTRL, HIFN_PUCTRL_DMAENA); + hifn_wait_puc(dev); +} + +static void hifn_stop_device(struct hifn_device *dev) +{ + hifn_write_1(dev, HIFN_1_DMA_CSR, + HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS | + HIFN_DMACSR_S_CTRL_DIS | HIFN_DMACSR_C_CTRL_DIS); + hifn_write_0(dev, HIFN_0_PUIER, 0); + hifn_write_1(dev, HIFN_1_DMA_IER, 0); +} + +static void hifn_reset_dma(struct hifn_device *dev, int full) +{ + hifn_stop_device(dev); + + /* + * Setting poll frequency and others to 0. + */ + hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | + HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); + mdelay(1); + + /* + * Reset DMA. + */ + if (full) { + hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MODE); + mdelay(1); + } else { + hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MODE | + HIFN_DMACNFG_MSTRESET); + hifn_reset_puc(dev); + } + + hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | + HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); + + hifn_reset_puc(dev); +} + +static u32 hifn_next_signature(u_int32_t a, u_int cnt) +{ + int i; + u32 v; + + for (i = 0; i < cnt; i++) { + + /* get the parity */ + v = a & 0x80080125; + v ^= v >> 16; + v ^= v >> 8; + v ^= v >> 4; + v ^= v >> 2; + v ^= v >> 1; + + a = (v & 1) ^ (a << 1); + } + + return a; +} + +static struct pci2id { + u_short pci_vendor; + u_short pci_prod; + char card_id[13]; +} pci2id[] = { + { + PCI_VENDOR_ID_HIFN, + PCI_DEVICE_ID_HIFN_7955, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00 } + }, + { + PCI_VENDOR_ID_HIFN, + PCI_DEVICE_ID_HIFN_7956, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00 } + } +}; + +#if defined(CONFIG_HW_RANDOM) || defined(CONFIG_HW_RANDOM_MODULE) +static int hifn_rng_data_present(struct hwrng *rng, int wait) +{ + struct hifn_device *dev = (struct hifn_device *)rng->priv; + s64 nsec; + + nsec = ktime_to_ns(ktime_sub(ktime_get(), dev->rngtime)); + nsec -= dev->rng_wait_time; + if (nsec <= 0) + return 1; + if (!wait) + return 0; + ndelay(nsec); + return 1; +} + +static int hifn_rng_data_read(struct hwrng *rng, u32 *data) +{ + struct hifn_device *dev = (struct hifn_device *)rng->priv; + + *data = hifn_read_1(dev, HIFN_1_RNG_DATA); + dev->rngtime = ktime_get(); + return 4; +} + +static int hifn_register_rng(struct hifn_device *dev) +{ + /* + * We must wait at least 256 Pk_clk cycles between two reads of the rng. + */ + dev->rng_wait_time = DIV_ROUND_UP(NSEC_PER_SEC, dev->pk_clk_freq) * + 256; + + dev->rng.name = dev->name; + dev->rng.data_present = hifn_rng_data_present, + dev->rng.data_read = hifn_rng_data_read, + dev->rng.priv = (unsigned long)dev; + + return hwrng_register(&dev->rng); +} + +static void hifn_unregister_rng(struct hifn_device *dev) +{ + hwrng_unregister(&dev->rng); +} +#else +#define hifn_register_rng(dev) 0 +#define hifn_unregister_rng(dev) +#endif + +static int hifn_init_pubrng(struct hifn_device *dev) +{ + int i; + + hifn_write_1(dev, HIFN_1_PUB_RESET, hifn_read_1(dev, HIFN_1_PUB_RESET) | + HIFN_PUBRST_RESET); + + for (i=100; i > 0; --i) { + mdelay(1); + + if ((hifn_read_1(dev, HIFN_1_PUB_RESET) & HIFN_PUBRST_RESET) == 0) + break; + } + + if (!i) + dprintk("Chip %s: Failed to initialise public key engine.\n", + dev->name); + else { + hifn_write_1(dev, HIFN_1_PUB_IEN, HIFN_PUBIEN_DONE); + dev->dmareg |= HIFN_DMAIER_PUBDONE; + hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg); + + dprintk("Chip %s: Public key engine has been sucessfully " + "initialised.\n", dev->name); + } + + /* + * Enable RNG engine. + */ + + hifn_write_1(dev, HIFN_1_RNG_CONFIG, + hifn_read_1(dev, HIFN_1_RNG_CONFIG) | HIFN_RNGCFG_ENA); + dprintk("Chip %s: RNG engine has been successfully initialised.\n", + dev->name); + +#if defined(CONFIG_HW_RANDOM) || defined(CONFIG_HW_RANDOM_MODULE) + /* First value must be discarded */ + hifn_read_1(dev, HIFN_1_RNG_DATA); + dev->rngtime = ktime_get(); +#endif + return 0; +} + +static int hifn_enable_crypto(struct hifn_device *dev) +{ + u32 dmacfg, addr; + char *offtbl = NULL; + int i; + + for (i = 0; i < sizeof(pci2id)/sizeof(pci2id[0]); i++) { + if (pci2id[i].pci_vendor == dev->pdev->vendor && + pci2id[i].pci_prod == dev->pdev->device) { + offtbl = pci2id[i].card_id; + break; + } + } + + if (offtbl == NULL) { + dprintk("Chip %s: Unknown card!\n", dev->name); + return -ENODEV; + } + + dmacfg = hifn_read_1(dev, HIFN_1_DMA_CNFG); + + hifn_write_1(dev, HIFN_1_DMA_CNFG, + HIFN_DMACNFG_UNLOCK | HIFN_DMACNFG_MSTRESET | + HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); + mdelay(1); + addr = hifn_read_1(dev, HIFN_1_UNLOCK_SECRET1); + mdelay(1); + hifn_write_1(dev, HIFN_1_UNLOCK_SECRET2, 0); + mdelay(1); + + for (i=0; i<12; ++i) { + addr = hifn_next_signature(addr, offtbl[i] + 0x101); + hifn_write_1(dev, HIFN_1_UNLOCK_SECRET2, addr); + + mdelay(1); + } + hifn_write_1(dev, HIFN_1_DMA_CNFG, dmacfg); + + dprintk("Chip %s: %s.\n", dev->name, pci_name(dev->pdev)); + + return 0; +} + +static void hifn_init_dma(struct hifn_device *dev) +{ + struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; + u32 dptr = dev->desc_dma; + int i; + + for (i=0; i<HIFN_D_CMD_RSIZE; ++i) + dma->cmdr[i].p = __cpu_to_le32(dptr + + offsetof(struct hifn_dma, command_bufs[i][0])); + for (i=0; i<HIFN_D_RES_RSIZE; ++i) + dma->resr[i].p = __cpu_to_le32(dptr + + offsetof(struct hifn_dma, result_bufs[i][0])); + + /* + * Setup LAST descriptors. + */ + dma->cmdr[HIFN_D_CMD_RSIZE].p = __cpu_to_le32(dptr + + offsetof(struct hifn_dma, cmdr[0])); + dma->srcr[HIFN_D_SRC_RSIZE].p = __cpu_to_le32(dptr + + offsetof(struct hifn_dma, srcr[0])); + dma->dstr[HIFN_D_DST_RSIZE].p = __cpu_to_le32(dptr + + offsetof(struct hifn_dma, dstr[0])); + dma->resr[HIFN_D_RES_RSIZE].p = __cpu_to_le32(dptr + + offsetof(struct hifn_dma, resr[0])); + + dma->cmdu = dma->srcu = dma->dstu = dma->resu = 0; + dma->cmdi = dma->srci = dma->dsti = dma->resi = 0; + dma->cmdk = dma->srck = dma->dstk = dma->resk = 0; +} + +/* + * Initialize the PLL. We need to know the frequency of the reference clock + * to calculate the optimal multiplier. For PCI we assume 66MHz, since that + * allows us to operate without the risk of overclocking the chip. If it + * actually uses 33MHz, the chip will operate at half the speed, this can be + * overriden by specifying the frequency as module parameter (pci33). + * + * Unfortunately the PCI clock is not very suitable since the HIFN needs a + * stable clock and the PCI clock frequency may vary, so the default is the + * external clock. There is no way to find out its frequency, we default to + * 66MHz since according to Mike Ham of HiFn, almost every board in existence + * has an external crystal populated at 66MHz. + */ +static void hifn_init_pll(struct hifn_device *dev) +{ + unsigned int freq, m; + u32 pllcfg; + + pllcfg = HIFN_1_PLL | HIFN_PLL_RESERVED_1; + + if (strncmp(hifn_pll_ref, "ext", 3) == 0) + pllcfg |= HIFN_PLL_REF_CLK_PLL; + else + pllcfg |= HIFN_PLL_REF_CLK_HBI; + + if (hifn_pll_ref[3] != '\0') + freq = simple_strtoul(hifn_pll_ref + 3, NULL, 10); + else { + freq = 66; + printk(KERN_INFO "hifn795x: assuming %uMHz clock speed, " + "override with hifn_pll_ref=%.3s<frequency>\n", + freq, hifn_pll_ref); + } + + m = HIFN_PLL_FCK_MAX / freq; + + pllcfg |= (m / 2 - 1) << HIFN_PLL_ND_SHIFT; + if (m <= 8) + pllcfg |= HIFN_PLL_IS_1_8; + else + pllcfg |= HIFN_PLL_IS_9_12; + + /* Select clock source and enable clock bypass */ + hifn_write_1(dev, HIFN_1_PLL, pllcfg | + HIFN_PLL_PK_CLK_HBI | HIFN_PLL_PE_CLK_HBI | HIFN_PLL_BP); + + /* Let the chip lock to the input clock */ + mdelay(10); + + /* Disable clock bypass */ + hifn_write_1(dev, HIFN_1_PLL, pllcfg | + HIFN_PLL_PK_CLK_HBI | HIFN_PLL_PE_CLK_HBI); + + /* Switch the engines to the PLL */ + hifn_write_1(dev, HIFN_1_PLL, pllcfg | + HIFN_PLL_PK_CLK_PLL | HIFN_PLL_PE_CLK_PLL); + + /* + * The Fpk_clk runs at half the total speed. Its frequency is needed to + * calculate the minimum time between two reads of the rng. Since 33MHz + * is actually 33.333... we overestimate the frequency here, resulting + * in slightly larger intervals. + */ + dev->pk_clk_freq = 1000000 * (freq + 1) * m / 2; +} + +static void hifn_init_registers(struct hifn_device *dev) +{ + u32 dptr = dev->desc_dma; + + /* Initialization magic... */ + hifn_write_0(dev, HIFN_0_PUCTRL, HIFN_PUCTRL_DMAENA); + hifn_write_0(dev, HIFN_0_FIFOCNFG, HIFN_FIFOCNFG_THRESHOLD); + hifn_write_0(dev, HIFN_0_PUIER, HIFN_PUIER_DSTOVER); + + /* write all 4 ring address registers */ + hifn_write_1(dev, HIFN_1_DMA_CRAR, __cpu_to_le32(dptr + + offsetof(struct hifn_dma, cmdr[0]))); + hifn_write_1(dev, HIFN_1_DMA_SRAR, __cpu_to_le32(dptr + + offsetof(struct hifn_dma, srcr[0]))); + hifn_write_1(dev, HIFN_1_DMA_DRAR, __cpu_to_le32(dptr + + offsetof(struct hifn_dma, dstr[0]))); + hifn_write_1(dev, HIFN_1_DMA_RRAR, __cpu_to_le32(dptr + + offsetof(struct hifn_dma, resr[0]))); + + mdelay(2); +#if 0 + hifn_write_1(dev, HIFN_1_DMA_CSR, + HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS | + HIFN_DMACSR_S_CTRL_DIS | HIFN_DMACSR_C_CTRL_DIS | + HIFN_DMACSR_D_ABORT | HIFN_DMACSR_D_DONE | HIFN_DMACSR_D_LAST | + HIFN_DMACSR_D_WAIT | HIFN_DMACSR_D_OVER | + HIFN_DMACSR_R_ABORT | HIFN_DMACSR_R_DONE | HIFN_DMACSR_R_LAST | + HIFN_DMACSR_R_WAIT | HIFN_DMACSR_R_OVER | + HIFN_DMACSR_S_ABORT | HIFN_DMACSR_S_DONE | HIFN_DMACSR_S_LAST | + HIFN_DMACSR_S_WAIT | + HIFN_DMACSR_C_ABORT | HIFN_DMACSR_C_DONE | HIFN_DMACSR_C_LAST | + HIFN_DMACSR_C_WAIT | + HIFN_DMACSR_ENGINE | + HIFN_DMACSR_PUBDONE); +#else + hifn_write_1(dev, HIFN_1_DMA_CSR, + HIFN_DMACSR_C_CTRL_ENA | HIFN_DMACSR_S_CTRL_ENA | + HIFN_DMACSR_D_CTRL_ENA | HIFN_DMACSR_R_CTRL_ENA | + HIFN_DMACSR_D_ABORT | HIFN_DMACSR_D_DONE | HIFN_DMACSR_D_LAST | + HIFN_DMACSR_D_WAIT | HIFN_DMACSR_D_OVER | + HIFN_DMACSR_R_ABORT | HIFN_DMACSR_R_DONE | HIFN_DMACSR_R_LAST | + HIFN_DMACSR_R_WAIT | HIFN_DMACSR_R_OVER | + HIFN_DMACSR_S_ABORT | HIFN_DMACSR_S_DONE | HIFN_DMACSR_S_LAST | + HIFN_DMACSR_S_WAIT | + HIFN_DMACSR_C_ABORT | HIFN_DMACSR_C_DONE | HIFN_DMACSR_C_LAST | + HIFN_DMACSR_C_WAIT | + HIFN_DMACSR_ENGINE | + HIFN_DMACSR_PUBDONE); +#endif + hifn_read_1(dev, HIFN_1_DMA_CSR); + + dev->dmareg |= HIFN_DMAIER_R_DONE | HIFN_DMAIER_C_ABORT | + HIFN_DMAIER_D_OVER | HIFN_DMAIER_R_OVER | + HIFN_DMAIER_S_ABORT | HIFN_DMAIER_D_ABORT | HIFN_DMAIER_R_ABORT | + HIFN_DMAIER_ENGINE; + dev->dmareg &= ~HIFN_DMAIER_C_WAIT; + + hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg); + hifn_read_1(dev, HIFN_1_DMA_IER); +#if 0 + hifn_write_0(dev, HIFN_0_PUCNFG, HIFN_PUCNFG_ENCCNFG | + HIFN_PUCNFG_DRFR_128 | HIFN_PUCNFG_TCALLPHASES | + HIFN_PUCNFG_TCDRVTOTEM | HIFN_PUCNFG_BUS32 | + HIFN_PUCNFG_DRAM); +#else + hifn_write_0(dev, HIFN_0_PUCNFG, 0x10342); +#endif + hifn_init_pll(dev); + + hifn_write_0(dev, HIFN_0_PUISR, HIFN_PUISR_DSTOVER); + hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | + HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE | HIFN_DMACNFG_LAST | + ((HIFN_POLL_FREQUENCY << 16 ) & HIFN_DMACNFG_POLLFREQ) | + ((HIFN_POLL_SCALAR << 8) & HIFN_DMACNFG_POLLINVAL)); +} + +static int hifn_setup_base_command(struct hifn_device *dev, u8 *buf, + unsigned dlen, unsigned slen, u16 mask, u8 snum) +{ + struct hifn_base_command *base_cmd; + u8 *buf_pos = buf; + + base_cmd = (struct hifn_base_command *)buf_pos; + base_cmd->masks = __cpu_to_le16(mask); + base_cmd->total_source_count = + __cpu_to_le16(slen & HIFN_BASE_CMD_LENMASK_LO); + base_cmd->total_dest_count = + __cpu_to_le16(dlen & HIFN_BASE_CMD_LENMASK_LO); + + dlen >>= 16; + slen >>= 16; + base_cmd->session_num = __cpu_to_le16(snum | + ((slen << HIFN_BASE_CMD_SRCLEN_S) & HIFN_BASE_CMD_SRCLEN_M) | + ((dlen << HIFN_BASE_CMD_DSTLEN_S) & HIFN_BASE_CMD_DSTLEN_M)); + + return sizeof(struct hifn_base_command); +} + +static int hifn_setup_crypto_command(struct hifn_device *dev, + u8 *buf, unsigned dlen, unsigned slen, + u8 *key, int keylen, u8 *iv, int ivsize, u16 mode) +{ + struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; + struct hifn_crypt_command *cry_cmd; + u8 *buf_pos = buf; + u16 cmd_len; + + cry_cmd = (struct hifn_crypt_command *)buf_pos; + + cry_cmd->source_count = __cpu_to_le16(dlen & 0xffff); + dlen >>= 16; + cry_cmd->masks = __cpu_to_le16(mode | + ((dlen << HIFN_CRYPT_CMD_SRCLEN_S) & + HIFN_CRYPT_CMD_SRCLEN_M)); + cry_cmd->header_skip = 0; + cry_cmd->reserved = 0; + + buf_pos += sizeof(struct hifn_crypt_command); + + dma->cmdu++; + if (dma->cmdu > 1) { + dev->dmareg |= HIFN_DMAIER_C_WAIT; + hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg); + } + + if (keylen) { + memcpy(buf_pos, key, keylen); + buf_pos += keylen; + } + if (ivsize) { + memcpy(buf_pos, iv, ivsize); + buf_pos += ivsize; + } + + cmd_len = buf_pos - buf; + + return cmd_len; +} + +static int hifn_setup_src_desc(struct hifn_device *dev, struct page *page, + unsigned int offset, unsigned int size) +{ + struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; + int idx; + dma_addr_t addr; + + addr = pci_map_page(dev->pdev, page, offset, size, PCI_DMA_TODEVICE); + + idx = dma->srci; + + dma->srcr[idx].p = __cpu_to_le32(addr); + dma->srcr[idx].l = __cpu_to_le32(size) | HIFN_D_VALID | + HIFN_D_MASKDONEIRQ | HIFN_D_NOINVALID | HIFN_D_LAST; + + if (++idx == HIFN_D_SRC_RSIZE) { + dma->srcr[idx].l = __cpu_to_le32(HIFN_D_VALID | + HIFN_D_JUMP | + HIFN_D_MASKDONEIRQ | HIFN_D_LAST); + idx = 0; + } + + dma->srci = idx; + dma->srcu++; + + if (!(dev->flags & HIFN_FLAG_SRC_BUSY)) { + hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_S_CTRL_ENA); + dev->flags |= HIFN_FLAG_SRC_BUSY; + } + + return size; +} + +static void hifn_setup_res_desc(struct hifn_device *dev) +{ + struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; + + dma->resr[dma->resi].l = __cpu_to_le32(HIFN_USED_RESULT | + HIFN_D_VALID | HIFN_D_LAST); + /* + * dma->resr[dma->resi].l = __cpu_to_le32(HIFN_MAX_RESULT | HIFN_D_VALID | + * HIFN_D_LAST | HIFN_D_NOINVALID); + */ + + if (++dma->resi == HIFN_D_RES_RSIZE) { + dma->resr[HIFN_D_RES_RSIZE].l = __cpu_to_le32(HIFN_D_VALID | + HIFN_D_JUMP | HIFN_D_MASKDONEIRQ | HIFN_D_LAST); + dma->resi = 0; + } + + dma->resu++; + + if (!(dev->flags & HIFN_FLAG_RES_BUSY)) { + hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_R_CTRL_ENA); + dev->flags |= HIFN_FLAG_RES_BUSY; + } +} + +static void hifn_setup_dst_desc(struct hifn_device *dev, struct page *page, + unsigned offset, unsigned size) +{ + struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; + int idx; + dma_addr_t addr; + + addr = pci_map_page(dev->pdev, page, offset, size, PCI_DMA_FROMDEVICE); + + idx = dma->dsti; + dma->dstr[idx].p = __cpu_to_le32(addr); + dma->dstr[idx].l = __cpu_to_le32(size | HIFN_D_VALID | + HIFN_D_MASKDONEIRQ | HIFN_D_NOINVALID | HIFN_D_LAST); + + if (++idx == HIFN_D_DST_RSIZE) { + dma->dstr[idx].l = __cpu_to_le32(HIFN_D_VALID | + HIFN_D_JUMP | HIFN_D_MASKDONEIRQ | + HIFN_D_LAST | HIFN_D_NOINVALID); + idx = 0; + } + dma->dsti = idx; + dma->dstu++; + + if (!(dev->flags & HIFN_FLAG_DST_BUSY)) { + hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_D_CTRL_ENA); + dev->flags |= HIFN_FLAG_DST_BUSY; + } +} + +static int hifn_setup_dma(struct hifn_device *dev, struct page *spage, unsigned int soff, + struct page *dpage, unsigned int doff, unsigned int nbytes, void *priv, + struct hifn_context *ctx) +{ + struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; + int cmd_len, sa_idx; + u8 *buf, *buf_pos; + u16 mask; + + dprintk("%s: spage: %p, soffset: %u, dpage: %p, doffset: %u, nbytes: %u, priv: %p, ctx: %p.\n", + dev->name, spage, soff, dpage, doff, nbytes, priv, ctx); + + sa_idx = dma->resi; + + hifn_setup_src_desc(dev, spage, soff, nbytes); + + buf_pos = buf = dma->command_bufs[dma->cmdi]; + + mask = 0; + switch (ctx->op) { + case ACRYPTO_OP_DECRYPT: + mask = HIFN_BASE_CMD_CRYPT | HIFN_BASE_CMD_DECODE; + break; + case ACRYPTO_OP_ENCRYPT: + mask = HIFN_BASE_CMD_CRYPT; + break; + case ACRYPTO_OP_HMAC: + mask = HIFN_BASE_CMD_MAC; + break; + default: + goto err_out; + } + + buf_pos += hifn_setup_base_command(dev, buf_pos, nbytes, + nbytes, mask, dev->snum); + + if (ctx->op == ACRYPTO_OP_ENCRYPT || ctx->op == ACRYPTO_OP_DECRYPT) { + u16 md = 0; + + if (ctx->keysize) + md |= HIFN_CRYPT_CMD_NEW_KEY; + if (ctx->iv && ctx->mode != ACRYPTO_MODE_ECB) + md |= HIFN_CRYPT_CMD_NEW_IV; + + switch (ctx->mode) { + case ACRYPTO_MODE_ECB: + md |= HIFN_CRYPT_CMD_MODE_ECB; + break; + case ACRYPTO_MODE_CBC: + md |= HIFN_CRYPT_CMD_MODE_CBC; + break; + case ACRYPTO_MODE_CFB: + md |= HIFN_CRYPT_CMD_MODE_CFB; + break; + case ACRYPTO_MODE_OFB: + md |= HIFN_CRYPT_CMD_MODE_OFB; + break; + default: + goto err_out; + } + + switch (ctx->type) { + case ACRYPTO_TYPE_AES_128: + if (ctx->keysize != 16) + goto err_out; + md |= HIFN_CRYPT_CMD_KSZ_128 | + HIFN_CRYPT_CMD_ALG_AES; + break; + case ACRYPTO_TYPE_AES_192: + if (ctx->keysize != 24) + goto err_out; + md |= HIFN_CRYPT_CMD_KSZ_192 | + HIFN_CRYPT_CMD_ALG_AES; + break; + case ACRYPTO_TYPE_AES_256: + if (ctx->keysize != 32) + goto err_out; + md |= HIFN_CRYPT_CMD_KSZ_256 | + HIFN_CRYPT_CMD_ALG_AES; + break; + case ACRYPTO_TYPE_3DES: + if (ctx->keysize != 24) + goto err_out; + md |= HIFN_CRYPT_CMD_ALG_3DES; + break; + case ACRYPTO_TYPE_DES: + if (ctx->keysize != 8) + goto err_out; + md |= HIFN_CRYPT_CMD_ALG_DES; + break; + default: + goto err_out; + } + + buf_pos += hifn_setup_crypto_command(dev, buf_pos, + nbytes, nbytes, ctx->key, ctx->keysize, + ctx->iv, ctx->ivsize, md); + } + + dev->sa[sa_idx] = priv; + + cmd_len = buf_pos - buf; + dma->cmdr[dma->cmdi].l = __cpu_to_le32(cmd_len | HIFN_D_VALID | + HIFN_D_LAST | HIFN_D_MASKDONEIRQ); + + if (++dma->cmdi == HIFN_D_CMD_RSIZE) { + dma->cmdr[dma->cmdi].l = __cpu_to_le32(HIFN_MAX_COMMAND | + HIFN_D_VALID | HIFN_D_LAST | + HIFN_D_MASKDONEIRQ | HIFN_D_JUMP); + dma->cmdi = 0; + } else + dma->cmdr[dma->cmdi-1].l |= __cpu_to_le32(HIFN_D_VALID); + + if (!(dev->flags & HIFN_FLAG_CMD_BUSY)) { + hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_C_CTRL_ENA); + dev->flags |= HIFN_FLAG_CMD_BUSY; + } + + hifn_setup_dst_desc(dev, dpage, doff, nbytes); + hifn_setup_res_desc(dev); + + return 0; + +err_out: + return -EINVAL; +} + +static int ablkcipher_walk_init(struct ablkcipher_walk *w, + int num, gfp_t gfp_flags) +{ + int i; + + num = min(ASYNC_SCATTERLIST_CACHE, num); + sg_init_table(w->cache, num); + + w->num = 0; + for (i=0; i<num; ++i) { + struct page *page = alloc_page(gfp_flags); + struct scatterlist *s; + + if (!page) + break; + + s = &w->cache[i]; + + sg_set_page(s, page, PAGE_SIZE, 0); + w->num++; + } + + return i; +} + +static void ablkcipher_walk_exit(struct ablkcipher_walk *w) +{ + int i; + + for (i=0; i<w->num; ++i) { + struct scatterlist *s = &w->cache[i]; + + __free_page(sg_page(s)); + + s->length = 0; + } + + w->num = 0; +} + +static int ablkcipher_add(void *daddr, unsigned int *drestp, struct scatterlist *src, + unsigned int size, unsigned int *nbytesp) +{ + unsigned int copy, drest = *drestp, nbytes = *nbytesp; + int idx = 0; + void *saddr; + + if (drest < size || size > nbytes) + return -EINVAL; + + while (size) { + copy = min(drest, src->length); + + saddr = kmap_atomic(sg_page(src), KM_SOFTIRQ1); + memcpy(daddr, saddr + src->offset, copy); + kunmap_atomic(saddr, KM_SOFTIRQ1); + + size -= copy; + drest -= copy; + nbytes -= copy; + daddr += copy; + + dprintk("%s: copy: %u, size: %u, drest: %u, nbytes: %u.\n", + __func__, copy, size, drest, nbytes); + + src++; + idx++; + } + + *nbytesp = nbytes; + *drestp = drest; + + return idx; +} + +static int ablkcipher_walk(struct ablkcipher_request *req, + struct ablkcipher_walk *w) +{ + unsigned blocksize = + crypto_ablkcipher_blocksize(crypto_ablkcipher_reqtfm(req)); + unsigned alignmask = + crypto_ablkcipher_alignmask(crypto_ablkcipher_reqtfm(req)); + struct scatterlist *src, *dst, *t; + void *daddr; + unsigned int nbytes = req->nbytes, offset, copy, diff; + int idx, tidx, err; + + tidx = idx = 0; + offset = 0; + while (nbytes) { + if (idx >= w->num && (w->flags & ASYNC_FLAGS_MISALIGNED)) + return -EINVAL; + + src = &req->src[idx]; + dst = &req->dst[idx]; + + dprintk("\n%s: slen: %u, dlen: %u, soff: %u, doff: %u, offset: %u, " + "blocksize: %u, nbytes: %u.\n", + __func__, src->length, dst->length, src->offset, + dst->offset, offset, blocksize, nbytes); + + if (src->length & (blocksize - 1) || + src->offset & (alignmask - 1) || + dst->length & (blocksize - 1) || + dst->offset & (alignmask - 1) || + offset) { + unsigned slen = src->length - offset; + unsigned dlen = PAGE_SIZE; + + t = &w->cache[idx]; + + daddr = kmap_atomic(sg_page(t), KM_SOFTIRQ0); + err = ablkcipher_add(daddr, &dlen, src, slen, &nbytes); + if (err < 0) + goto err_out_unmap; + + idx += err; + + copy = slen & ~(blocksize - 1); + diff = slen & (blocksize - 1); + + if (dlen < nbytes) { + /* + * Destination page does not have enough space + * to put there additional blocksized chunk, + * so we mark that page as containing only + * blocksize aligned chunks: + * t->length = (slen & ~(blocksize - 1)); + * and increase number of bytes to be processed + * in next chunk: + * nbytes += diff; + */ + nbytes += diff; + + /* + * Temporary of course... + * Kick author if you will catch this one. + */ + printk(KERN_ERR "%s: dlen: %u, nbytes: %u," + "slen: %u, offset: %u.\n", + __func__, dlen, nbytes, slen, offset); + printk(KERN_ERR "%s: please contact author to fix this " + "issue, generally you should not catch " + "this path under any condition but who " + "knows how did you use crypto code.\n" + "Thank you.\n", __func__); + BUG(); + } else { + copy += diff + nbytes; + + src = &req->src[idx]; + + err = ablkcipher_add(daddr + slen, &dlen, src, nbytes, &nbytes); + if (err < 0) + goto err_out_unmap; + + idx += err; + } + + t->length = copy; + t->offset = offset; + + kunmap_atomic(daddr, KM_SOFTIRQ0); + } else { + nbytes -= src->length; + idx++; + } + + tidx++; + } + + return tidx; + +err_out_unmap: + kunmap_atomic(daddr, KM_SOFTIRQ0); + return err; +} + +static int hifn_setup_session(struct ablkcipher_request *req) +{ + struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm); + struct hifn_device *dev = ctx->dev; + struct page *spage, *dpage; + unsigned long soff, doff, flags; + unsigned int nbytes = req->nbytes, idx = 0, len; + int err = -EINVAL, sg_num; + struct scatterlist *src, *dst, *t; + unsigned blocksize = + crypto_ablkcipher_blocksize(crypto_ablkcipher_reqtfm(req)); + unsigned alignmask = + crypto_ablkcipher_alignmask(crypto_ablkcipher_reqtfm(req)); + + if (ctx->iv && !ctx->ivsize && ctx->mode != ACRYPTO_MODE_ECB) + goto err_out_exit; + + ctx->walk.flags = 0; + + while (nbytes) { + src = &req->src[idx]; + dst = &req->dst[idx]; + + if (src->length & (blocksize - 1) || + src->offset & (alignmask - 1) || + dst->length & (blocksize - 1) || + dst->offset & (alignmask - 1)) { + ctx->walk.flags |= ASYNC_FLAGS_MISALIGNED; + } + + nbytes -= src->length; + idx++; + } + + if (ctx->walk.flags & ASYNC_FLAGS_MISALIGNED) { + err = ablkcipher_walk_init(&ctx->walk, idx, GFP_ATOMIC); + if (err < 0) + return err; + } + + nbytes = req->nbytes; + idx = 0; + + sg_num = ablkcipher_walk(req, &ctx->walk); + + atomic_set(&ctx->sg_num, sg_num); + + spin_lock_irqsave(&dev->lock, flags); + if (dev->started + sg_num > HIFN_QUEUE_LENGTH) { + err = -EAGAIN; + goto err_out; + } + + dev->snum++; + dev->started += sg_num; + + while (nbytes) { + src = &req->src[idx]; + dst = &req->dst[idx]; + t = &ctx->walk.cache[idx]; + + if (t->length) { + spage = dpage = sg_page(t); + soff = doff = 0; + len = t->length; + } else { + spage = sg_page(src); + soff = src->offset; + + dpage = sg_page(dst); + doff = dst->offset; + + len = dst->length; + } + + idx++; + + err = hifn_setup_dma(dev, spage, soff, dpage, doff, nbytes, + req, ctx); + if (err) + goto err_out; + + nbytes -= len; + } + + dev->active = HIFN_DEFAULT_ACTIVE_NUM; + spin_unlock_irqrestore(&dev->lock, flags); + + return 0; + +err_out: + spin_unlock_irqrestore(&dev->lock, flags); +err_out_exit: + if (err && printk_ratelimit()) + dprintk("%s: iv: %p [%d], key: %p [%d], mode: %u, op: %u, " + "type: %u, err: %d.\n", + dev->name, ctx->iv, ctx->ivsize, + ctx->key, ctx->keysize, + ctx->mode, ctx->op, ctx->type, err); + + return err; +} + +static int hifn_test(struct hifn_device *dev, int encdec, u8 snum) +{ + int n, err; + u8 src[16]; + struct hifn_context ctx; + u8 fips_aes_ecb_from_zero[16] = { + 0x66, 0xE9, 0x4B, 0xD4, + 0xEF, 0x8A, 0x2C, 0x3B, + 0x88, 0x4C, 0xFA, 0x59, + 0xCA, 0x34, 0x2B, 0x2E}; + + memset(src, 0, sizeof(src)); + memset(ctx.key, 0, sizeof(ctx.key)); + + ctx.dev = dev; + ctx.keysize = 16; + ctx.ivsize = 0; + ctx.iv = NULL; + ctx.op = (encdec)?ACRYPTO_OP_ENCRYPT:ACRYPTO_OP_DECRYPT; + ctx.mode = ACRYPTO_MODE_ECB; + ctx.type = ACRYPTO_TYPE_AES_128; + atomic_set(&ctx.sg_num, 1); + + err = hifn_setup_dma(dev, + virt_to_page(src), offset_in_page(src), + virt_to_page(src), offset_in_page(src), + sizeof(src), NULL, &ctx); + if (err) + goto err_out; + + msleep(200); + + dprintk("%s: decoded: ", dev->name); + for (n=0; n<sizeof(src); ++n) + dprintk("%02x ", src[n]); + dprintk("\n"); + dprintk("%s: FIPS : ", dev->name); + for (n=0; n<sizeof(fips_aes_ecb_from_zero); ++n) + dprintk("%02x ", fips_aes_ecb_from_zero[n]); + dprintk("\n"); + + if (!memcmp(src, fips_aes_ecb_from_zero, sizeof(fips_aes_ecb_from_zero))) { + printk(KERN_INFO "%s: AES 128 ECB test has been successfully " + "passed.\n", dev->name); + return 0; + } + +err_out: + printk(KERN_INFO "%s: AES 128 ECB test has been failed.\n", dev->name); + return -1; +} + +static int hifn_start_device(struct hifn_device *dev) +{ + int err; + + hifn_reset_dma(dev, 1); + + err = hifn_enable_crypto(dev); + if (err) + return err; + + hifn_reset_puc(dev); + + hifn_init_dma(dev); + + hifn_init_registers(dev); + + hifn_init_pubrng(dev); + + return 0; +} + +static int ablkcipher_get(void *saddr, unsigned int *srestp, unsigned int offset, + struct scatterlist *dst, unsigned int size, unsigned int *nbytesp) +{ + unsigned int srest = *srestp, nbytes = *nbytesp, copy; + void *daddr; + int idx = 0; + + if (srest < size || size > nbytes) + return -EINVAL; + + while (size) { + + copy = min(dst->length, srest); + + daddr = kmap_atomic(sg_page(dst), KM_IRQ0); + memcpy(daddr + dst->offset + offset, saddr, copy); + kunmap_atomic(daddr, KM_IRQ0); + + nbytes -= copy; + size -= copy; + srest -= copy; + saddr += copy; + offset = 0; + + dprintk("%s: copy: %u, size: %u, srest: %u, nbytes: %u.\n", + __func__, copy, size, srest, nbytes); + + dst++; + idx++; + } + + *nbytesp = nbytes; + *srestp = srest; + + return idx; +} + +static void hifn_process_ready(struct ablkcipher_request *req, int error) +{ + struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm); + struct hifn_device *dev; + + dprintk("%s: req: %p, ctx: %p.\n", __func__, req, ctx); + + dev = ctx->dev; + dprintk("%s: req: %p, started: %d, sg_num: %d.\n", + __func__, req, dev->started, atomic_read(&ctx->sg_num)); + + if (--dev->started < 0) + BUG(); + + if (atomic_dec_and_test(&ctx->sg_num)) { + unsigned int nbytes = req->nbytes; + int idx = 0, err; + struct scatterlist *dst, *t; + void *saddr; + + if (ctx->walk.flags & ASYNC_FLAGS_MISALIGNED) { + while (nbytes) { + t = &ctx->walk.cache[idx]; + dst = &req->dst[idx]; + + dprintk("\n%s: sg_page(t): %p, t->length: %u, " + "sg_page(dst): %p, dst->length: %u, " + "nbytes: %u.\n", + __func__, sg_page(t), t->length, + sg_page(dst), dst->length, nbytes); + + if (!t->length) { + nbytes -= dst->length; + idx++; + continue; + } + + saddr = kmap_atomic(sg_page(t), KM_IRQ1); + + err = ablkcipher_get(saddr, &t->length, t->offset, + dst, nbytes, &nbytes); + if (err < 0) { + kunmap_atomic(saddr, KM_IRQ1); + break; + } + + idx += err; + kunmap_atomic(saddr, KM_IRQ1); + } + + ablkcipher_walk_exit(&ctx->walk); + } + + req->base.complete(&req->base, error); + } +} + +static void hifn_check_for_completion(struct hifn_device *dev, int error) +{ + int i; + struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; + + for (i=0; i<HIFN_D_RES_RSIZE; ++i) { + struct hifn_desc *d = &dma->resr[i]; + + if (!(d->l & __cpu_to_le32(HIFN_D_VALID)) && dev->sa[i]) { + dev->success++; + dev->reset = 0; + hifn_process_ready(dev->sa[i], error); + dev->sa[i] = NULL; + } + + if (d->l & __cpu_to_le32(HIFN_D_DESTOVER | HIFN_D_OVER)) + if (printk_ratelimit()) + printk("%s: overflow detected [d: %u, o: %u] " + "at %d resr: l: %08x, p: %08x.\n", + dev->name, + !!(d->l & __cpu_to_le32(HIFN_D_DESTOVER)), + !!(d->l & __cpu_to_le32(HIFN_D_OVER)), + i, d->l, d->p); + } +} + +static void hifn_clear_rings(struct hifn_device *dev) +{ + struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; + int i, u; + + dprintk("%s: ring cleanup 1: i: %d.%d.%d.%d, u: %d.%d.%d.%d, " + "k: %d.%d.%d.%d.\n", + dev->name, + dma->cmdi, dma->srci, dma->dsti, dma->resi, + dma->cmdu, dma->srcu, dma->dstu, dma->resu, + dma->cmdk, dma->srck, dma->dstk, dma->resk); + + i = dma->resk; u = dma->resu; + while (u != 0) { + if (dma->resr[i].l & __cpu_to_le32(HIFN_D_VALID)) + break; + + if (i != HIFN_D_RES_RSIZE) + u--; + + if (++i == (HIFN_D_RES_RSIZE + 1)) + i = 0; + } + dma->resk = i; dma->resu = u; + + i = dma->srck; u = dma->srcu; + while (u != 0) { + if (i == HIFN_D_SRC_RSIZE) + i = 0; + if (dma->srcr[i].l & __cpu_to_le32(HIFN_D_VALID)) + break; + i++, u--; + } + dma->srck = i; dma->srcu = u; + + i = dma->cmdk; u = dma->cmdu; + while (u != 0) { + if (dma->cmdr[i].l & __cpu_to_le32(HIFN_D_VALID)) + break; + if (i != HIFN_D_CMD_RSIZE) + u--; + if (++i == (HIFN_D_CMD_RSIZE + 1)) + i = 0; + } + dma->cmdk = i; dma->cmdu = u; + + i = dma->dstk; u = dma->dstu; + while (u != 0) { + if (i == HIFN_D_DST_RSIZE) + i = 0; + if (dma->dstr[i].l & __cpu_to_le32(HIFN_D_VALID)) + break; + i++, u--; + } + dma->dstk = i; dma->dstu = u; + + dprintk("%s: ring cleanup 2: i: %d.%d.%d.%d, u: %d.%d.%d.%d, " + "k: %d.%d.%d.%d.\n", + dev->name, + dma->cmdi, dma->srci, dma->dsti, dma->resi, + dma->cmdu, dma->srcu, dma->dstu, dma->resu, + dma->cmdk, dma->srck, dma->dstk, dma->resk); +} + +static void hifn_work(struct work_struct *work) +{ + struct delayed_work *dw = container_of(work, struct delayed_work, work); + struct hifn_device *dev = container_of(dw, struct hifn_device, work); + unsigned long flags; + int reset = 0; + u32 r = 0; + + spin_lock_irqsave(&dev->lock, flags); + if (dev->active == 0) { + struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; + + if (dma->cmdu == 0 && (dev->flags & HIFN_FLAG_CMD_BUSY)) { + dev->flags &= ~HIFN_FLAG_CMD_BUSY; + r |= HIFN_DMACSR_C_CTRL_DIS; + } + if (dma->srcu == 0 && (dev->flags & HIFN_FLAG_SRC_BUSY)) { + dev->flags &= ~HIFN_FLAG_SRC_BUSY; + r |= HIFN_DMACSR_S_CTRL_DIS; + } + if (dma->dstu == 0 && (dev->flags & HIFN_FLAG_DST_BUSY)) { + dev->flags &= ~HIFN_FLAG_DST_BUSY; + r |= HIFN_DMACSR_D_CTRL_DIS; + } + if (dma->resu == 0 && (dev->flags & HIFN_FLAG_RES_BUSY)) { + dev->flags &= ~HIFN_FLAG_RES_BUSY; + r |= HIFN_DMACSR_R_CTRL_DIS; + } + if (r) + hifn_write_1(dev, HIFN_1_DMA_CSR, r); + } else + dev->active--; + + if (dev->prev_success == dev->success && dev->started) + reset = 1; + dev->prev_success = dev->success; + spin_unlock_irqrestore(&dev->lock, flags); + + if (reset) { + dprintk("%s: r: %08x, active: %d, started: %d, " + "success: %lu: reset: %d.\n", + dev->name, r, dev->active, dev->started, + dev->success, reset); + + if (++dev->reset >= 5) { + dprintk("%s: really hard reset.\n", dev->name); + hifn_reset_dma(dev, 1); + hifn_stop_device(dev); + hifn_start_device(dev); + dev->reset = 0; + } + + spin_lock_irqsave(&dev->lock, flags); + hifn_check_for_completion(dev, -EBUSY); + hifn_clear_rings(dev); + dev->started = 0; + spin_unlock_irqrestore(&dev->lock, flags); + } + + schedule_delayed_work(&dev->work, HZ); +} + +static irqreturn_t hifn_interrupt(int irq, void *data) +{ + struct hifn_device *dev = (struct hifn_device *)data; + struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; + u32 dmacsr, restart; + + dmacsr = hifn_read_1(dev, HIFN_1_DMA_CSR); + + dprintk("%s: 1 dmacsr: %08x, dmareg: %08x, res: %08x [%d], " + "i: %d.%d.%d.%d, u: %d.%d.%d.%d.\n", + dev->name, dmacsr, dev->dmareg, dmacsr & dev->dmareg, dma->cmdi, + dma->cmdu, dma->srcu, dma->dstu, dma->resu, + dma->cmdi, dma->srci, dma->dsti, dma->resi); + + if ((dmacsr & dev->dmareg) == 0) + return IRQ_NONE; + + hifn_write_1(dev, HIFN_1_DMA_CSR, dmacsr & dev->dmareg); + + if (dmacsr & HIFN_DMACSR_ENGINE) + hifn_write_0(dev, HIFN_0_PUISR, hifn_read_0(dev, HIFN_0_PUISR)); + if (dmacsr & HIFN_DMACSR_PUBDONE) + hifn_write_1(dev, HIFN_1_PUB_STATUS, + hifn_read_1(dev, HIFN_1_PUB_STATUS) | HIFN_PUBSTS_DONE); + + restart = dmacsr & (HIFN_DMACSR_R_OVER | HIFN_DMACSR_D_OVER); + if (restart) { + u32 puisr = hifn_read_0(dev, HIFN_0_PUISR); + + if (printk_ratelimit()) + printk("%s: overflow: r: %d, d: %d, puisr: %08x, d: %u.\n", + dev->name, !!(dmacsr & HIFN_DMACSR_R_OVER), + !!(dmacsr & HIFN_DMACSR_D_OVER), + puisr, !!(puisr & HIFN_PUISR_DSTOVER)); + if (!!(puisr & HIFN_PUISR_DSTOVER)) + hifn_write_0(dev, HIFN_0_PUISR, HIFN_PUISR_DSTOVER); + hifn_write_1(dev, HIFN_1_DMA_CSR, dmacsr & (HIFN_DMACSR_R_OVER | + HIFN_DMACSR_D_OVER)); + } + + restart = dmacsr & (HIFN_DMACSR_C_ABORT | HIFN_DMACSR_S_ABORT | + HIFN_DMACSR_D_ABORT | HIFN_DMACSR_R_ABORT); + if (restart) { + if (printk_ratelimit()) + printk("%s: abort: c: %d, s: %d, d: %d, r: %d.\n", + dev->name, !!(dmacsr & HIFN_DMACSR_C_ABORT), + !!(dmacsr & HIFN_DMACSR_S_ABORT), + !!(dmacsr & HIFN_DMACSR_D_ABORT), + !!(dmacsr & HIFN_DMACSR_R_ABORT)); + hifn_reset_dma(dev, 1); + hifn_init_dma(dev); + hifn_init_registers(dev); + } + + if ((dmacsr & HIFN_DMACSR_C_WAIT) && (dma->cmdu == 0)) { + dprintk("%s: wait on command.\n", dev->name); + dev->dmareg &= ~(HIFN_DMAIER_C_WAIT); + hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg); + } + + tasklet_schedule(&dev->tasklet); + hifn_clear_rings(dev); + + return IRQ_HANDLED; +} + +static void hifn_flush(struct hifn_device *dev) +{ + unsigned long flags; + struct crypto_async_request *async_req; + struct hifn_context *ctx; + struct ablkcipher_request *req; + struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; + int i; + + spin_lock_irqsave(&dev->lock, flags); + for (i=0; i<HIFN_D_RES_RSIZE; ++i) { + struct hifn_desc *d = &dma->resr[i]; + + if (dev->sa[i]) { + hifn_process_ready(dev->sa[i], + (d->l & __cpu_to_le32(HIFN_D_VALID))?-ENODEV:0); + } + } + + while ((async_req = crypto_dequeue_request(&dev->queue))) { + ctx = crypto_tfm_ctx(async_req->tfm); + req = container_of(async_req, struct ablkcipher_request, base); + + hifn_process_ready(req, -ENODEV); + } + spin_unlock_irqrestore(&dev->lock, flags); +} + +static int hifn_setkey(struct crypto_ablkcipher *cipher, const u8 *key, + unsigned int len) +{ + struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher); + struct hifn_context *ctx = crypto_tfm_ctx(tfm); + struct hifn_device *dev = ctx->dev; + + if (len > HIFN_MAX_CRYPT_KEY_LENGTH) { + crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -1; + } + + if (len == HIFN_DES_KEY_LENGTH) { + u32 tmp[DES_EXPKEY_WORDS]; + int ret = des_ekey(tmp, key); + + if (unlikely(ret == 0) && (tfm->crt_flags & CRYPTO_TFM_REQ_WEAK_KEY)) { + tfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY; + return -EINVAL; + } + } + + dev->flags &= ~HIFN_FLAG_OLD_KEY; + + memcpy(ctx->key, key, len); + ctx->keysize = len; + + return 0; +} + +static int hifn_handle_req(struct ablkcipher_request *req) +{ + struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm); + struct hifn_device *dev = ctx->dev; + int err = -EAGAIN; + + if (dev->started + DIV_ROUND_UP(req->nbytes, PAGE_SIZE) <= HIFN_QUEUE_LENGTH) + err = hifn_setup_session(req); + + if (err == -EAGAIN) { + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + err = ablkcipher_enqueue_request(&dev->queue, req); + spin_unlock_irqrestore(&dev->lock, flags); + } + + return err; +} + +static int hifn_setup_crypto_req(struct ablkcipher_request *req, u8 op, + u8 type, u8 mode) +{ + struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm); + unsigned ivsize; + + ivsize = crypto_ablkcipher_ivsize(crypto_ablkcipher_reqtfm(req)); + + if (req->info && mode != ACRYPTO_MODE_ECB) { + if (type == ACRYPTO_TYPE_AES_128) + ivsize = HIFN_AES_IV_LENGTH; + else if (type == ACRYPTO_TYPE_DES) + ivsize = HIFN_DES_KEY_LENGTH; + else if (type == ACRYPTO_TYPE_3DES) + ivsize = HIFN_3DES_KEY_LENGTH; + } + + if (ctx->keysize != 16 && type == ACRYPTO_TYPE_AES_128) { + if (ctx->keysize == 24) + type = ACRYPTO_TYPE_AES_192; + else if (ctx->keysize == 32) + type = ACRYPTO_TYPE_AES_256; + } + + ctx->op = op; + ctx->mode = mode; + ctx->type = type; + ctx->iv = req->info; + ctx->ivsize = ivsize; + + /* + * HEAVY TODO: needs to kick Herbert XU to write documentation. + * HEAVY TODO: needs to kick Herbert XU to write documentation. + * HEAVY TODO: needs to kick Herbert XU to write documentation. + */ + + return hifn_handle_req(req); +} + +static int hifn_process_queue(struct hifn_device *dev) +{ + struct crypto_async_request *async_req; + struct hifn_context *ctx; + struct ablkcipher_request *req; + unsigned long flags; + int err = 0; + + while (dev->started < HIFN_QUEUE_LENGTH) { + spin_lock_irqsave(&dev->lock, flags); + async_req = crypto_dequeue_request(&dev->queue); + spin_unlock_irqrestore(&dev->lock, flags); + + if (!async_req) + break; + + ctx = crypto_tfm_ctx(async_req->tfm); + req = container_of(async_req, struct ablkcipher_request, base); + + err = hifn_handle_req(req); + if (err) + break; + } + + return err; +} + +static int hifn_setup_crypto(struct ablkcipher_request *req, u8 op, + u8 type, u8 mode) +{ + int err; + struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm); + struct hifn_device *dev = ctx->dev; + + err = hifn_setup_crypto_req(req, op, type, mode); + if (err) + return err; + + if (dev->started < HIFN_QUEUE_LENGTH && dev->queue.qlen) + err = hifn_process_queue(dev); + + return err; +} + +/* + * AES ecryption functions. + */ +static inline int hifn_encrypt_aes_ecb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, + ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_ECB); +} +static inline int hifn_encrypt_aes_cbc(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, + ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CBC); +} +static inline int hifn_encrypt_aes_cfb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, + ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CFB); +} +static inline int hifn_encrypt_aes_ofb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, + ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_OFB); +} + +/* + * AES decryption functions. + */ +static inline int hifn_decrypt_aes_ecb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, + ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_ECB); +} +static inline int hifn_decrypt_aes_cbc(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, + ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CBC); +} +static inline int hifn_decrypt_aes_cfb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, + ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CFB); +} +static inline int hifn_decrypt_aes_ofb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, + ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_OFB); +} + +/* + * DES ecryption functions. + */ +static inline int hifn_encrypt_des_ecb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, + ACRYPTO_TYPE_DES, ACRYPTO_MODE_ECB); +} +static inline int hifn_encrypt_des_cbc(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, + ACRYPTO_TYPE_DES, ACRYPTO_MODE_CBC); +} +static inline int hifn_encrypt_des_cfb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, + ACRYPTO_TYPE_DES, ACRYPTO_MODE_CFB); +} +static inline int hifn_encrypt_des_ofb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, + ACRYPTO_TYPE_DES, ACRYPTO_MODE_OFB); +} + +/* + * DES decryption functions. + */ +static inline int hifn_decrypt_des_ecb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, + ACRYPTO_TYPE_DES, ACRYPTO_MODE_ECB); +} +static inline int hifn_decrypt_des_cbc(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, + ACRYPTO_TYPE_DES, ACRYPTO_MODE_CBC); +} +static inline int hifn_decrypt_des_cfb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, + ACRYPTO_TYPE_DES, ACRYPTO_MODE_CFB); +} +static inline int hifn_decrypt_des_ofb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, + ACRYPTO_TYPE_DES, ACRYPTO_MODE_OFB); +} + +/* + * 3DES ecryption functions. + */ +static inline int hifn_encrypt_3des_ecb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, + ACRYPTO_TYPE_3DES, ACRYPTO_MODE_ECB); +} +static inline int hifn_encrypt_3des_cbc(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, + ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CBC); +} +static inline int hifn_encrypt_3des_cfb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, + ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CFB); +} +static inline int hifn_encrypt_3des_ofb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, + ACRYPTO_TYPE_3DES, ACRYPTO_MODE_OFB); +} + +/* + * 3DES decryption functions. + */ +static inline int hifn_decrypt_3des_ecb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, + ACRYPTO_TYPE_3DES, ACRYPTO_MODE_ECB); +} +static inline int hifn_decrypt_3des_cbc(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, + ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CBC); +} +static inline int hifn_decrypt_3des_cfb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, + ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CFB); +} +static inline int hifn_decrypt_3des_ofb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, + ACRYPTO_TYPE_3DES, ACRYPTO_MODE_OFB); +} + +struct hifn_alg_template +{ + char name[CRYPTO_MAX_ALG_NAME]; + char drv_name[CRYPTO_MAX_ALG_NAME]; + unsigned int bsize; + struct ablkcipher_alg ablkcipher; +}; + +static struct hifn_alg_template hifn_alg_templates[] = { + /* + * 3DES ECB, CBC, CFB and OFB modes. + */ + { + .name = "cfb(des3_ede)", .drv_name = "hifn-3des", .bsize = 8, + .ablkcipher = { + .min_keysize = HIFN_3DES_KEY_LENGTH, + .max_keysize = HIFN_3DES_KEY_LENGTH, + .setkey = hifn_setkey, + .encrypt = hifn_encrypt_3des_cfb, + .decrypt = hifn_decrypt_3des_cfb, + }, + }, + { + .name = "ofb(des3_ede)", .drv_name = "hifn-3des", .bsize = 8, + .ablkcipher = { + .min_keysize = HIFN_3DES_KEY_LENGTH, + .max_keysize = HIFN_3DES_KEY_LENGTH, + .setkey = hifn_setkey, + .encrypt = hifn_encrypt_3des_ofb, + .decrypt = hifn_decrypt_3des_ofb, + }, + }, + { + .name = "cbc(des3_ede)", .drv_name = "hifn-3des", .bsize = 8, + .ablkcipher = { + .min_keysize = HIFN_3DES_KEY_LENGTH, + .max_keysize = HIFN_3DES_KEY_LENGTH, + .setkey = hifn_setkey, + .encrypt = hifn_encrypt_3des_cbc, + .decrypt = hifn_decrypt_3des_cbc, + }, + }, + { + .name = "ecb(des3_ede)", .drv_name = "hifn-3des", .bsize = 8, + .ablkcipher = { + .min_keysize = HIFN_3DES_KEY_LENGTH, + .max_keysize = HIFN_3DES_KEY_LENGTH, + .setkey = hifn_setkey, + .encrypt = hifn_encrypt_3des_ecb, + .decrypt = hifn_decrypt_3des_ecb, + }, + }, + + /* + * DES ECB, CBC, CFB and OFB modes. + */ + { + .name = "cfb(des)", .drv_name = "hifn-des", .bsize = 8, + .ablkcipher = { + .min_keysize = HIFN_DES_KEY_LENGTH, + .max_keysize = HIFN_DES_KEY_LENGTH, + .setkey = hifn_setkey, + .encrypt = hifn_encrypt_des_cfb, + .decrypt = hifn_decrypt_des_cfb, + }, + }, + { + .name = "ofb(des)", .drv_name = "hifn-des", .bsize = 8, + .ablkcipher = { + .min_keysize = HIFN_DES_KEY_LENGTH, + .max_keysize = HIFN_DES_KEY_LENGTH, + .setkey = hifn_setkey, + .encrypt = hifn_encrypt_des_ofb, + .decrypt = hifn_decrypt_des_ofb, + }, + }, + { + .name = "cbc(des)", .drv_name = "hifn-des", .bsize = 8, + .ablkcipher = { + .min_keysize = HIFN_DES_KEY_LENGTH, + .max_keysize = HIFN_DES_KEY_LENGTH, + .setkey = hifn_setkey, + .encrypt = hifn_encrypt_des_cbc, + .decrypt = hifn_decrypt_des_cbc, + }, + }, + { + .name = "ecb(des)", .drv_name = "hifn-des", .bsize = 8, + .ablkcipher = { + .min_keysize = HIFN_DES_KEY_LENGTH, + .max_keysize = HIFN_DES_KEY_LENGTH, + .setkey = hifn_setkey, + .encrypt = hifn_encrypt_des_ecb, + .decrypt = hifn_decrypt_des_ecb, + }, + }, + + /* + * AES ECB, CBC, CFB and OFB modes. + */ + { + .name = "ecb(aes)", .drv_name = "hifn-aes", .bsize = 16, + .ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = hifn_setkey, + .encrypt = hifn_encrypt_aes_ecb, + .decrypt = hifn_decrypt_aes_ecb, + }, + }, + { + .name = "cbc(aes)", .drv_name = "hifn-aes", .bsize = 16, + .ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = hifn_setkey, + .encrypt = hifn_encrypt_aes_cbc, + .decrypt = hifn_decrypt_aes_cbc, + }, + }, + { + .name = "cfb(aes)", .drv_name = "hifn-aes", .bsize = 16, + .ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = hifn_setkey, + .encrypt = hifn_encrypt_aes_cfb, + .decrypt = hifn_decrypt_aes_cfb, + }, + }, + { + .name = "ofb(aes)", .drv_name = "hifn-aes", .bsize = 16, + .ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = hifn_setkey, + .encrypt = hifn_encrypt_aes_ofb, + .decrypt = hifn_decrypt_aes_ofb, + }, + }, +}; + +static int hifn_cra_init(struct crypto_tfm *tfm) +{ + struct crypto_alg *alg = tfm->__crt_alg; + struct hifn_crypto_alg *ha = crypto_alg_to_hifn(alg); + struct hifn_context *ctx = crypto_tfm_ctx(tfm); + + ctx->dev = ha->dev; + + return 0; +} + +static int hifn_alg_alloc(struct hifn_device *dev, struct hifn_alg_template *t) +{ + struct hifn_crypto_alg *alg; + int err; + + alg = kzalloc(sizeof(struct hifn_crypto_alg), GFP_KERNEL); + if (!alg) + return -ENOMEM; + + snprintf(alg->alg.cra_name, CRYPTO_MAX_ALG_NAME, "%s", t->name); + snprintf(alg->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", t->drv_name); + + alg->alg.cra_priority = 300; + alg->alg.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC; + alg->alg.cra_blocksize = t->bsize; + alg->alg.cra_ctxsize = sizeof(struct hifn_context); + alg->alg.cra_alignmask = 15; + if (t->bsize == 8) + alg->alg.cra_alignmask = 3; + alg->alg.cra_type = &crypto_ablkcipher_type; + alg->alg.cra_module = THIS_MODULE; + alg->alg.cra_u.ablkcipher = t->ablkcipher; + alg->alg.cra_init = hifn_cra_init; + + alg->dev = dev; + + list_add_tail(&alg->entry, &dev->alg_list); + + err = crypto_register_alg(&alg->alg); + if (err) { + list_del(&alg->entry); + kfree(alg); + } + + return err; +} + +static void hifn_unregister_alg(struct hifn_device *dev) +{ + struct hifn_crypto_alg *a, *n; + + list_for_each_entry_safe(a, n, &dev->alg_list, entry) { + list_del(&a->entry); + crypto_unregister_alg(&a->alg); + kfree(a); + } +} + +static int hifn_register_alg(struct hifn_device *dev) +{ + int i, err; + + for (i=0; i<ARRAY_SIZE(hifn_alg_templates); ++i) { + err = hifn_alg_alloc(dev, &hifn_alg_templates[i]); + if (err) + goto err_out_exit; + } + + return 0; + +err_out_exit: + hifn_unregister_alg(dev); + return err; +} + +static void hifn_tasklet_callback(unsigned long data) +{ + struct hifn_device *dev = (struct hifn_device *)data; + + /* + * This is ok to call this without lock being held, + * althogh it modifies some parameters used in parallel, + * (like dev->success), but they are used in process + * context or update is atomic (like setting dev->sa[i] to NULL). + */ + hifn_check_for_completion(dev, 0); +} + +static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + int err, i; + struct hifn_device *dev; + char name[8]; + + err = pci_enable_device(pdev); + if (err) + return err; + pci_set_master(pdev); + + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (err) + goto err_out_disable_pci_device; + + snprintf(name, sizeof(name), "hifn%d", + atomic_inc_return(&hifn_dev_number)-1); + + err = pci_request_regions(pdev, name); + if (err) + goto err_out_disable_pci_device; + + if (pci_resource_len(pdev, 0) < HIFN_BAR0_SIZE || + pci_resource_len(pdev, 1) < HIFN_BAR1_SIZE || + pci_resource_len(pdev, 2) < HIFN_BAR2_SIZE) { + dprintk("%s: Broken hardware - I/O regions are too small.\n", + pci_name(pdev)); + err = -ENODEV; + goto err_out_free_regions; + } + + dev = kzalloc(sizeof(struct hifn_device) + sizeof(struct crypto_alg), + GFP_KERNEL); + if (!dev) { + err = -ENOMEM; + goto err_out_free_regions; + } + + INIT_LIST_HEAD(&dev->alg_list); + + snprintf(dev->name, sizeof(dev->name), "%s", name); + spin_lock_init(&dev->lock); + + for (i=0; i<3; ++i) { + unsigned long addr, size; + + addr = pci_resource_start(pdev, i); + size = pci_resource_len(pdev, i); + + dev->bar[i] = ioremap_nocache(addr, size); + if (!dev->bar[i]) + goto err_out_unmap_bars; + } + + dev->result_mem = __get_free_pages(GFP_KERNEL, HIFN_MAX_RESULT_ORDER); + if (!dev->result_mem) { + dprintk("Failed to allocate %d pages for result_mem.\n", + HIFN_MAX_RESULT_ORDER); + goto err_out_unmap_bars; + } + memset((void *)dev->result_mem, 0, PAGE_SIZE*(1<<HIFN_MAX_RESULT_ORDER)); + + dev->dst = pci_map_single(pdev, (void *)dev->result_mem, + PAGE_SIZE << HIFN_MAX_RESULT_ORDER, PCI_DMA_FROMDEVICE); + + dev->desc_virt = pci_alloc_consistent(pdev, sizeof(struct hifn_dma), + &dev->desc_dma); + if (!dev->desc_virt) { + dprintk("Failed to allocate descriptor rings.\n"); + goto err_out_free_result_pages; + } + memset(dev->desc_virt, 0, sizeof(struct hifn_dma)); + + dev->pdev = pdev; + dev->irq = pdev->irq; + + for (i=0; i<HIFN_D_RES_RSIZE; ++i) + dev->sa[i] = NULL; + + pci_set_drvdata(pdev, dev); + + tasklet_init(&dev->tasklet, hifn_tasklet_callback, (unsigned long)dev); + + crypto_init_queue(&dev->queue, 1); + + err = request_irq(dev->irq, hifn_interrupt, IRQF_SHARED, dev->name, dev); + if (err) { + dprintk("Failed to request IRQ%d: err: %d.\n", dev->irq, err); + dev->irq = 0; + goto err_out_free_desc; + } + + err = hifn_start_device(dev); + if (err) + goto err_out_free_irq; + + err = hifn_test(dev, 1, 0); + if (err) + goto err_out_stop_device; + + err = hifn_register_rng(dev); + if (err) + goto err_out_stop_device; + + err = hifn_register_alg(dev); + if (err) + goto err_out_unregister_rng; + + INIT_DELAYED_WORK(&dev->work, hifn_work); + schedule_delayed_work(&dev->work, HZ); + + dprintk("HIFN crypto accelerator card at %s has been " + "successfully registered as %s.\n", + pci_name(pdev), dev->name); + + return 0; + +err_out_unregister_rng: + hifn_unregister_rng(dev); +err_out_stop_device: + hifn_reset_dma(dev, 1); + hifn_stop_device(dev); +err_out_free_irq: + free_irq(dev->irq, dev->name); + tasklet_kill(&dev->tasklet); +err_out_free_desc: + pci_free_consistent(pdev, sizeof(struct hifn_dma), + dev->desc_virt, dev->desc_dma); + +err_out_free_result_pages: + pci_unmap_single(pdev, dev->dst, PAGE_SIZE << HIFN_MAX_RESULT_ORDER, + PCI_DMA_FROMDEVICE); + free_pages(dev->result_mem, HIFN_MAX_RESULT_ORDER); + +err_out_unmap_bars: + for (i=0; i<3; ++i) + if (dev->bar[i]) + iounmap(dev->bar[i]); + +err_out_free_regions: + pci_release_regions(pdev); + +err_out_disable_pci_device: + pci_disable_device(pdev); + + return err; +} + +static void hifn_remove(struct pci_dev *pdev) +{ + int i; + struct hifn_device *dev; + + dev = pci_get_drvdata(pdev); + + if (dev) { + cancel_delayed_work(&dev->work); + flush_scheduled_work(); + + hifn_unregister_rng(dev); + hifn_unregister_alg(dev); + hifn_reset_dma(dev, 1); + hifn_stop_device(dev); + + free_irq(dev->irq, dev->name); + tasklet_kill(&dev->tasklet); + + hifn_flush(dev); + + pci_free_consistent(pdev, sizeof(struct hifn_dma), + dev->desc_virt, dev->desc_dma); + pci_unmap_single(pdev, dev->dst, + PAGE_SIZE << HIFN_MAX_RESULT_ORDER, + PCI_DMA_FROMDEVICE); + free_pages(dev->result_mem, HIFN_MAX_RESULT_ORDER); + for (i=0; i<3; ++i) + if (dev->bar[i]) + iounmap(dev->bar[i]); + + kfree(dev); + } + + pci_release_regions(pdev); + pci_disable_device(pdev); +} + +static struct pci_device_id hifn_pci_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_HIFN, PCI_DEVICE_ID_HIFN_7955) }, + { PCI_DEVICE(PCI_VENDOR_ID_HIFN, PCI_DEVICE_ID_HIFN_7956) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, hifn_pci_tbl); + +static struct pci_driver hifn_pci_driver = { + .name = "hifn795x", + .id_table = hifn_pci_tbl, + .probe = hifn_probe, + .remove = __devexit_p(hifn_remove), +}; + +static int __devinit hifn_init(void) +{ + unsigned int freq; + int err; + + if (strncmp(hifn_pll_ref, "ext", 3) && + strncmp(hifn_pll_ref, "pci", 3)) { + printk(KERN_ERR "hifn795x: invalid hifn_pll_ref clock, " + "must be pci or ext"); + return -EINVAL; + } + + /* + * For the 7955/7956 the reference clock frequency must be in the + * range of 20MHz-100MHz. For the 7954 the upper bound is 66.67MHz, + * but this chip is currently not supported. + */ + if (hifn_pll_ref[3] != '\0') { + freq = simple_strtoul(hifn_pll_ref + 3, NULL, 10); + if (freq < 20 || freq > 100) { + printk(KERN_ERR "hifn795x: invalid hifn_pll_ref " + "frequency, must be in the range " + "of 20-100"); + return -EINVAL; + } + } + + err = pci_register_driver(&hifn_pci_driver); + if (err < 0) { + dprintk("Failed to register PCI driver for %s device.\n", + hifn_pci_driver.name); + return -ENODEV; + } + + printk(KERN_INFO "Driver for HIFN 795x crypto accelerator chip " + "has been successfully registered.\n"); + + return 0; +} + +static void __devexit hifn_fini(void) +{ + pci_unregister_driver(&hifn_pci_driver); + + printk(KERN_INFO "Driver for HIFN 795x crypto accelerator chip " + "has been successfully unregistered.\n"); +} + +module_init(hifn_init); +module_exit(hifn_fini); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>"); +MODULE_DESCRIPTION("Driver for HIFN 795x crypto accelerator chip."); diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c index 5f7e71810489..2f3ad3f7dfea 100644 --- a/drivers/crypto/padlock-aes.c +++ b/drivers/crypto/padlock-aes.c @@ -44,6 +44,7 @@ */ #include <crypto/algapi.h> +#include <crypto/aes.h> #include <linux/module.h> #include <linux/init.h> #include <linux/types.h> @@ -53,9 +54,6 @@ #include <asm/byteorder.h> #include "padlock.h" -#define AES_MIN_KEY_SIZE 16 /* in uint8_t units */ -#define AES_MAX_KEY_SIZE 32 /* ditto */ -#define AES_BLOCK_SIZE 16 /* ditto */ #define AES_EXTENDED_KEY_SIZE 64 /* in uint32_t units */ #define AES_EXTENDED_KEY_SIZE_B (AES_EXTENDED_KEY_SIZE * sizeof(uint32_t)) @@ -419,6 +417,11 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, /* ====== Encryption/decryption routines ====== */ /* These are the real call to PadLock. */ +static inline void padlock_reset_key(void) +{ + asm volatile ("pushfl; popfl"); +} + static inline void padlock_xcrypt(const u8 *input, u8 *output, void *key, void *control_word) { @@ -439,8 +442,6 @@ static void aes_crypt_copy(const u8 *in, u8 *out, u32 *key, struct cword *cword) static inline void aes_crypt(const u8 *in, u8 *out, u32 *key, struct cword *cword) { - asm volatile ("pushfl; popfl"); - /* padlock_xcrypt requires at least two blocks of data. */ if (unlikely(!(((unsigned long)in ^ (PAGE_SIZE - AES_BLOCK_SIZE)) & (PAGE_SIZE - 1)))) { @@ -459,7 +460,6 @@ static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key, return; } - asm volatile ("pushfl; popfl"); /* enforce key reload. */ asm volatile ("test $1, %%cl;" "je 1f;" "lea -1(%%ecx), %%eax;" @@ -476,8 +476,6 @@ static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key, static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key, u8 *iv, void *control_word, u32 count) { - /* Enforce key reload. */ - asm volatile ("pushfl; popfl"); /* rep xcryptcbc */ asm volatile (".byte 0xf3,0x0f,0xa7,0xd0" : "+S" (input), "+D" (output), "+a" (iv) @@ -488,12 +486,14 @@ static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key, static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { struct aes_ctx *ctx = aes_ctx(tfm); + padlock_reset_key(); aes_crypt(in, out, ctx->E, &ctx->cword.encrypt); } static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { struct aes_ctx *ctx = aes_ctx(tfm); + padlock_reset_key(); aes_crypt(in, out, ctx->D, &ctx->cword.decrypt); } @@ -526,6 +526,8 @@ static int ecb_aes_encrypt(struct blkcipher_desc *desc, struct blkcipher_walk walk; int err; + padlock_reset_key(); + blkcipher_walk_init(&walk, dst, src, nbytes); err = blkcipher_walk_virt(desc, &walk); @@ -548,6 +550,8 @@ static int ecb_aes_decrypt(struct blkcipher_desc *desc, struct blkcipher_walk walk; int err; + padlock_reset_key(); + blkcipher_walk_init(&walk, dst, src, nbytes); err = blkcipher_walk_virt(desc, &walk); @@ -592,6 +596,8 @@ static int cbc_aes_encrypt(struct blkcipher_desc *desc, struct blkcipher_walk walk; int err; + padlock_reset_key(); + blkcipher_walk_init(&walk, dst, src, nbytes); err = blkcipher_walk_virt(desc, &walk); @@ -616,6 +622,8 @@ static int cbc_aes_decrypt(struct blkcipher_desc *desc, struct blkcipher_walk walk; int err; + padlock_reset_key(); + blkcipher_walk_init(&walk, dst, src, nbytes); err = blkcipher_walk_virt(desc, &walk); diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index d59b2f417306..bcf52df30339 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 @@ err_out: 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 70b837f23c43..53764577035f 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 3706b2bc0987..9aac88027fb3 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 @@ fail_out: 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 e0c4a4086055..7e1374afd967 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 69f5dddabddf..5b075da99145 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 6942e065e609..d168223db159 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 858a7b95933b..f4f709d1370b 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 b767603a07ba..ebfbb2947ae6 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 2994523be7bf..0cb3d2bb3ab9 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 7b9181b5469d..1495792d7917 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 90dc75be3418..511e4321c6b6 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 @@ fail_alloc: 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 @@ exit: 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 @@ exit: */ 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 3d4050681325..c864ef70fdf9 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 @@ err_remove_pma: 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 @@ err_put: 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 6a56d86a2951..c9e32b46387f 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 1f152ded1e3c..fc355981bbab 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 8786dd7922e4..bb1dc075f1d1 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 e1ad7cfc21fd..aa27ca9f03b1 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 @@ bail: 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 f449daef3eed..23ae66c76d47 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/capi/capidrv.c b/drivers/isdn/capi/capidrv.c index 48c1775ef5b3..cb42b690b45e 100644 --- a/drivers/isdn/capi/capidrv.c +++ b/drivers/isdn/capi/capidrv.c @@ -2332,13 +2332,14 @@ static int __init capidrv_init(void) static void __exit capidrv_exit(void) { - char rev[10]; + char rev[32]; char *p; if ((p = strchr(revision, ':')) != 0) { - strcpy(rev, p + 1); - p = strchr(rev, '$'); - *p = 0; + strncpy(rev, p + 1, sizeof(rev)); + rev[sizeof(rev)-1] = 0; + if ((p = strchr(rev, '$')) != 0) + *p = 0; } else { strcpy(rev, " ??? "); } diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index a0317abaeb11..02bdaf22d7ea 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 47c10b8f89b3..c0f372f1d761 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 5c742a526082..b7adde4324e4 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 6123c70153d3..ac420b17e16f 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 88c0fd657825..f2d24eb3208c 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 @@ out: *---------------------------------------------------------------*/ 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 cef9ebd5a046..c28a120b4161 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 e325fa71f38b..b7c8e7813865 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 e03f1bcd4f9f..f6b10dda31fd 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 ca8df8072d43..a8ad8a0ed5db 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 6497872df524..1a0e7978226a 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 de860bc6d3f5..4d8a4e248b34 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 2d1b3df95c5b..54380da343a5 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 8f77949f93dd..97544052e768 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 22ed96c4b7bd..a0cee86464ca 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 7d7758f3ad8c..57772bebff56 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 97bd9dc2e52e..419861cbc65e 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 ff37bf437a99..1d706eae3052 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 ebb09e98d215..de34aa9d3136 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 @@ parse_error: /** * 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 @@ parse_error: * 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 47d26b65e99a..750ebd7a4c10 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 @@ init_return: 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 01c351c176ac..47bb0e1ff3fa 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 @@ exit: 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 a080fedf0332..e32148a8fa12 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 6d1a21611818..c4fa35d1dd77 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 c5ca3134513a..5fd585293e79 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 5cf89a91da1e..15c18f5246d6 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 bbf3ee10da04..7e29b90a4f63 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 a63b75cf75e2..03d6a38464ef 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 f1e00ff54ce8..7e3ad4f3b343 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 c7ea9381db9f..d6e93f15440e 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 e01cbf152a81..86c3f6539a7d 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 8534cf09546c..06b1079b7f3d 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 005e62f8593b..651edd58906a 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 24271a871b8c..6325115e5b3d 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 7663841eb4cf..a3fdc57e2673 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 9d3105b64a7a..9c2df5c857cf 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 e8578d8cd35e..027455496745 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 93e9de46977a..682a6a48fec3 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 865f32b63b5c..cc246faa3590 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 c51f8e9312e0..7c3aaa9c5402 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 993f78c55221..e48a630ae266 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 c3bfa76765c4..2c7a8b5b4598 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 dcc6aead70f5..e3eb3556622b 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 3bf0278ea843..de3b31d0a37d 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 @@ out: 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 6a713b33992f..d26e2826ba5b 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -426,20 +426,19 @@ exit: } 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 6353a8384520..5c108c49cb8c 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 e5580bcb923a..0249aa4ae181 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 @@ out: 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 84f9f7dfdf5b..e5e80d1a4687 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/Makefile b/fs/gfs2/Makefile index 04ad0caebedb..8fff11058cee 100644 --- a/fs/gfs2/Makefile +++ b/fs/gfs2/Makefile @@ -2,7 +2,7 @@ obj-$(CONFIG_GFS2_FS) += gfs2.o gfs2-y := acl.o bmap.o daemon.o dir.o eaops.o eattr.o glock.o \ glops.o inode.o lm.o log.o lops.o locking.o main.o meta_io.o \ mount.o ops_address.o ops_dentry.o ops_export.o ops_file.o \ - ops_fstype.o ops_inode.o ops_super.o ops_vm.o quota.o \ + ops_fstype.o ops_inode.o ops_super.o quota.o \ recovery.o rgrp.o super.o sys.o trans.o util.o obj-$(CONFIG_GFS2_FS_LOCKING_NOLOCK) += locking/nolock/ diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 93fa427bb5f5..e4effc47abfc 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -59,7 +59,6 @@ struct strip_mine { static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh, u64 block, struct page *page) { - struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct inode *inode = &ip->i_inode; struct buffer_head *bh; int release = 0; @@ -95,7 +94,7 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh, set_buffer_uptodate(bh); if (!gfs2_is_jdata(ip)) mark_buffer_dirty(bh); - if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip)) + if (!gfs2_is_writeback(ip)) gfs2_trans_add_bh(ip->i_gl, bh, 0); if (release) { @@ -453,8 +452,8 @@ static inline void bmap_unlock(struct inode *inode, int create) * Returns: errno */ -int gfs2_block_map(struct inode *inode, u64 lblock, int create, - struct buffer_head *bh_map) +int gfs2_block_map(struct inode *inode, sector_t lblock, + struct buffer_head *bh_map, int create) { struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); @@ -470,6 +469,7 @@ int gfs2_block_map(struct inode *inode, u64 lblock, int create, unsigned int maxlen = bh_map->b_size >> inode->i_blkbits; struct metapath mp; u64 size; + struct buffer_head *dibh = NULL; BUG_ON(maxlen == 0); @@ -500,6 +500,8 @@ int gfs2_block_map(struct inode *inode, u64 lblock, int create, error = gfs2_meta_inode_buffer(ip, &bh); if (error) goto out_fail; + dibh = bh; + get_bh(dibh); for (x = 0; x < end_of_metadata; x++) { lookup_block(ip, bh, x, &mp, create, &new, &dblock); @@ -518,13 +520,8 @@ int gfs2_block_map(struct inode *inode, u64 lblock, int create, if (boundary) set_buffer_boundary(bh_map); if (new) { - struct buffer_head *dibh; - error = gfs2_meta_inode_buffer(ip, &dibh); - if (!error) { - gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(ip, dibh->b_data); - brelse(dibh); - } + gfs2_trans_add_bh(ip->i_gl, dibh, 1); + gfs2_dinode_out(ip, dibh->b_data); set_buffer_new(bh_map); goto out_brelse; } @@ -545,6 +542,8 @@ out_brelse: out_ok: error = 0; out_fail: + if (dibh) + brelse(dibh); bmap_unlock(inode, create); return error; } @@ -560,7 +559,7 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi BUG_ON(!new); bh.b_size = 1 << (inode->i_blkbits + 5); - ret = gfs2_block_map(inode, lblock, create, &bh); + ret = gfs2_block_map(inode, lblock, &bh, create); *extlen = bh.b_size >> inode->i_blkbits; *dblock = bh.b_blocknr; if (buffer_new(&bh)) @@ -684,7 +683,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, if (metadata) revokes = (height) ? sdp->sd_inptrs : sdp->sd_diptrs; - error = gfs2_rindex_hold(sdp, &ip->i_alloc.al_ri_gh); + error = gfs2_rindex_hold(sdp, &ip->i_alloc->al_ri_gh); if (error) return error; @@ -786,7 +785,7 @@ out_rg_gunlock: out_rlist: gfs2_rlist_free(&rlist); out: - gfs2_glock_dq_uninit(&ip->i_alloc.al_ri_gh); + gfs2_glock_dq_uninit(&ip->i_alloc->al_ri_gh); return error; } @@ -879,7 +878,6 @@ static int gfs2_block_truncate_page(struct address_space *mapping) { struct inode *inode = mapping->host; struct gfs2_inode *ip = GFS2_I(inode); - struct gfs2_sbd *sdp = GFS2_SB(inode); loff_t from = inode->i_size; unsigned long index = from >> PAGE_CACHE_SHIFT; unsigned offset = from & (PAGE_CACHE_SIZE-1); @@ -911,7 +909,7 @@ static int gfs2_block_truncate_page(struct address_space *mapping) err = 0; if (!buffer_mapped(bh)) { - gfs2_get_block(inode, iblock, bh, 0); + gfs2_block_map(inode, iblock, bh, 0); /* unmapped? It's a hole - nothing to do */ if (!buffer_mapped(bh)) goto unlock; @@ -931,7 +929,7 @@ static int gfs2_block_truncate_page(struct address_space *mapping) err = 0; } - if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip)) + if (!gfs2_is_writeback(ip)) gfs2_trans_add_bh(ip->i_gl, bh, 0); zero_user_page(page, offset, length, KM_USER0); @@ -1224,8 +1222,13 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset, do_div(lblock_stop, bsize); } else { unsigned int shift = sdp->sd_sb.sb_bsize_shift; + u64 end_of_file = (ip->i_di.di_size + sdp->sd_sb.sb_bsize - 1) >> shift; lblock = offset >> shift; lblock_stop = (offset + len + sdp->sd_sb.sb_bsize - 1) >> shift; + if (lblock_stop > end_of_file) { + *alloc_required = 1; + return 0; + } } for (; lblock < lblock_stop; lblock += extlen) { diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h index ac2fd04370dc..4e6cde2943bd 100644 --- a/fs/gfs2/bmap.h +++ b/fs/gfs2/bmap.h @@ -15,7 +15,7 @@ struct gfs2_inode; struct page; int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page); -int gfs2_block_map(struct inode *inode, u64 lblock, int create, struct buffer_head *bh); +int gfs2_block_map(struct inode *inode, sector_t lblock, struct buffer_head *bh, int create); int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen); int gfs2_truncatei(struct gfs2_inode *ip, u64 size); diff --git a/fs/gfs2/daemon.c b/fs/gfs2/daemon.c index 3731ab0771d5..e51991947d2c 100644 --- a/fs/gfs2/daemon.c +++ b/fs/gfs2/daemon.c @@ -83,56 +83,6 @@ int gfs2_recoverd(void *data) } /** - * gfs2_logd - Update log tail as Active Items get flushed to in-place blocks - * @sdp: Pointer to GFS2 superblock - * - * Also, periodically check to make sure that we're using the most recent - * journal index. - */ - -int gfs2_logd(void *data) -{ - struct gfs2_sbd *sdp = data; - struct gfs2_holder ji_gh; - unsigned long t; - int need_flush; - - while (!kthread_should_stop()) { - /* Advance the log tail */ - - t = sdp->sd_log_flush_time + - gfs2_tune_get(sdp, gt_log_flush_secs) * HZ; - - gfs2_ail1_empty(sdp, DIO_ALL); - gfs2_log_lock(sdp); - need_flush = sdp->sd_log_num_buf > gfs2_tune_get(sdp, gt_incore_log_blocks); - gfs2_log_unlock(sdp); - if (need_flush || time_after_eq(jiffies, t)) { - gfs2_log_flush(sdp, NULL); - sdp->sd_log_flush_time = jiffies; - } - - /* Check for latest journal index */ - - t = sdp->sd_jindex_refresh_time + - gfs2_tune_get(sdp, gt_jindex_refresh_secs) * HZ; - - if (time_after_eq(jiffies, t)) { - if (!gfs2_jindex_hold(sdp, &ji_gh)) - gfs2_glock_dq_uninit(&ji_gh); - sdp->sd_jindex_refresh_time = jiffies; - } - - t = gfs2_tune_get(sdp, gt_logd_secs) * HZ; - if (freezing(current)) - refrigerator(); - schedule_timeout_interruptible(t); - } - - return 0; -} - -/** * gfs2_quotad - Write cached quota changes into the quota file * @sdp: Pointer to GFS2 superblock * diff --git a/fs/gfs2/daemon.h b/fs/gfs2/daemon.h index 0de9b3557955..4be084fb6a62 100644 --- a/fs/gfs2/daemon.h +++ b/fs/gfs2/daemon.h @@ -12,7 +12,6 @@ int gfs2_glockd(void *data); int gfs2_recoverd(void *data); -int gfs2_logd(void *data); int gfs2_quotad(void *data); #endif /* __DAEMON_DOT_H__ */ diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 9949bb746a52..57e2ed932adc 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -1876,7 +1876,7 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, if (error) goto out; - error = gfs2_rindex_hold(sdp, &dip->i_alloc.al_ri_gh); + error = gfs2_rindex_hold(sdp, &dip->i_alloc->al_ri_gh); if (error) goto out_qs; @@ -1949,7 +1949,7 @@ out_rg_gunlock: gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs); out_rlist: gfs2_rlist_free(&rlist); - gfs2_glock_dq_uninit(&dip->i_alloc.al_ri_gh); + gfs2_glock_dq_uninit(&dip->i_alloc->al_ri_gh); out_qs: gfs2_quota_unhold(dip); out: diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c index aa8dbf303f6d..f114ba2b3557 100644 --- a/fs/gfs2/eaops.c +++ b/fs/gfs2/eaops.c @@ -56,46 +56,6 @@ unsigned int gfs2_ea_name2type(const char *name, const char **truncated_name) return type; } -static int user_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er) -{ - struct inode *inode = &ip->i_inode; - int error = permission(inode, MAY_READ, NULL); - if (error) - return error; - - return gfs2_ea_get_i(ip, er); -} - -static int user_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er) -{ - struct inode *inode = &ip->i_inode; - - if (S_ISREG(inode->i_mode) || - (S_ISDIR(inode->i_mode) && !(inode->i_mode & S_ISVTX))) { - int error = permission(inode, MAY_WRITE, NULL); - if (error) - return error; - } else - return -EPERM; - - return gfs2_ea_set_i(ip, er); -} - -static int user_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er) -{ - struct inode *inode = &ip->i_inode; - - if (S_ISREG(inode->i_mode) || - (S_ISDIR(inode->i_mode) && !(inode->i_mode & S_ISVTX))) { - int error = permission(inode, MAY_WRITE, NULL); - if (error) - return error; - } else - return -EPERM; - - return gfs2_ea_remove_i(ip, er); -} - static int system_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er) { if (!GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) && @@ -108,8 +68,6 @@ static int system_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er) GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len))) return -EOPNOTSUPP; - - return gfs2_ea_get_i(ip, er); } @@ -170,40 +128,10 @@ static int system_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er) return gfs2_ea_remove_i(ip, er); } -static int security_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er) -{ - struct inode *inode = &ip->i_inode; - int error = permission(inode, MAY_READ, NULL); - if (error) - return error; - - return gfs2_ea_get_i(ip, er); -} - -static int security_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er) -{ - struct inode *inode = &ip->i_inode; - int error = permission(inode, MAY_WRITE, NULL); - if (error) - return error; - - return gfs2_ea_set_i(ip, er); -} - -static int security_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er) -{ - struct inode *inode = &ip->i_inode; - int error = permission(inode, MAY_WRITE, NULL); - if (error) - return error; - - return gfs2_ea_remove_i(ip, er); -} - static const struct gfs2_eattr_operations gfs2_user_eaops = { - .eo_get = user_eo_get, - .eo_set = user_eo_set, - .eo_remove = user_eo_remove, + .eo_get = gfs2_ea_get_i, + .eo_set = gfs2_ea_set_i, + .eo_remove = gfs2_ea_remove_i, .eo_name = "user", }; @@ -215,9 +143,9 @@ const struct gfs2_eattr_operations gfs2_system_eaops = { }; static const struct gfs2_eattr_operations gfs2_security_eaops = { - .eo_get = security_eo_get, - .eo_set = security_eo_set, - .eo_remove = security_eo_remove, + .eo_get = gfs2_ea_get_i, + .eo_set = gfs2_ea_set_i, + .eo_remove = gfs2_ea_remove_i, .eo_name = "security", }; diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index 2a7435b5c4dc..bee99704ea10 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -1418,7 +1418,7 @@ out: static int ea_dealloc_block(struct gfs2_inode *ip) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); - struct gfs2_alloc *al = &ip->i_alloc; + struct gfs2_alloc *al = ip->i_alloc; struct gfs2_rgrpd *rgd; struct buffer_head *dibh; int error; diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index a37efe4aae6f..80e09c50590a 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1,6 +1,6 @@ /* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions @@ -217,7 +217,6 @@ int gfs2_glock_put(struct gfs2_glock *gl) if (atomic_dec_and_test(&gl->gl_ref)) { hlist_del(&gl->gl_list); write_unlock(gl_lock_addr(gl->gl_hash)); - BUG_ON(spin_is_locked(&gl->gl_spin)); gfs2_assert(sdp, gl->gl_state == LM_ST_UNLOCKED); gfs2_assert(sdp, list_empty(&gl->gl_reclaim)); gfs2_assert(sdp, list_empty(&gl->gl_holders)); @@ -346,7 +345,6 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, gl->gl_object = NULL; gl->gl_sbd = sdp; gl->gl_aspace = NULL; - lops_init_le(&gl->gl_le, &gfs2_glock_lops); INIT_DELAYED_WORK(&gl->gl_work, glock_work_func); /* If this glock protects actual on-disk data or metadata blocks, @@ -461,7 +459,6 @@ static void wait_on_holder(struct gfs2_holder *gh) static void gfs2_demote_wake(struct gfs2_glock *gl) { - BUG_ON(!spin_is_locked(&gl->gl_spin)); gl->gl_demote_state = LM_ST_EXCLUSIVE; clear_bit(GLF_DEMOTE, &gl->gl_flags); smp_mb__after_clear_bit(); @@ -507,21 +504,12 @@ static int rq_mutex(struct gfs2_holder *gh) static int rq_promote(struct gfs2_holder *gh) { struct gfs2_glock *gl = gh->gh_gl; - struct gfs2_sbd *sdp = gl->gl_sbd; if (!relaxed_state_ok(gl->gl_state, gh->gh_state, gh->gh_flags)) { if (list_empty(&gl->gl_holders)) { gl->gl_req_gh = gh; set_bit(GLF_LOCK, &gl->gl_flags); spin_unlock(&gl->gl_spin); - - if (atomic_read(&sdp->sd_reclaim_count) > - gfs2_tune_get(sdp, gt_reclaim_limit) && - !(gh->gh_flags & LM_FLAG_PRIORITY)) { - gfs2_reclaim_glock(sdp); - gfs2_reclaim_glock(sdp); - } - gfs2_glock_xmote_th(gh->gh_gl, gh); spin_lock(&gl->gl_spin); } @@ -567,7 +555,10 @@ static int rq_demote(struct gfs2_glock *gl) gfs2_demote_wake(gl); return 0; } + set_bit(GLF_LOCK, &gl->gl_flags); + set_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags); + if (gl->gl_demote_state == LM_ST_UNLOCKED || gl->gl_state != LM_ST_EXCLUSIVE) { spin_unlock(&gl->gl_spin); @@ -576,7 +567,9 @@ static int rq_demote(struct gfs2_glock *gl) spin_unlock(&gl->gl_spin); gfs2_glock_xmote_th(gl, NULL); } + spin_lock(&gl->gl_spin); + clear_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags); return 0; } @@ -598,23 +591,18 @@ static void run_queue(struct gfs2_glock *gl) if (!list_empty(&gl->gl_waiters1)) { gh = list_entry(gl->gl_waiters1.next, struct gfs2_holder, gh_list); - - if (test_bit(HIF_MUTEX, &gh->gh_iflags)) - blocked = rq_mutex(gh); - else - gfs2_assert_warn(gl->gl_sbd, 0); - + blocked = rq_mutex(gh); } else if (test_bit(GLF_DEMOTE, &gl->gl_flags)) { blocked = rq_demote(gl); + if (gl->gl_waiters2 && !blocked) { + set_bit(GLF_DEMOTE, &gl->gl_flags); + gl->gl_demote_state = LM_ST_UNLOCKED; + } + gl->gl_waiters2 = 0; } else if (!list_empty(&gl->gl_waiters3)) { gh = list_entry(gl->gl_waiters3.next, struct gfs2_holder, gh_list); - - if (test_bit(HIF_PROMOTE, &gh->gh_iflags)) - blocked = rq_promote(gh); - else - gfs2_assert_warn(gl->gl_sbd, 0); - + blocked = rq_promote(gh); } else break; @@ -632,27 +620,21 @@ static void run_queue(struct gfs2_glock *gl) static void gfs2_glmutex_lock(struct gfs2_glock *gl) { - struct gfs2_holder gh; - - gfs2_holder_init(gl, 0, 0, &gh); - set_bit(HIF_MUTEX, &gh.gh_iflags); - if (test_and_set_bit(HIF_WAIT, &gh.gh_iflags)) - BUG(); - spin_lock(&gl->gl_spin); if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) { + struct gfs2_holder gh; + + gfs2_holder_init(gl, 0, 0, &gh); + set_bit(HIF_WAIT, &gh.gh_iflags); list_add_tail(&gh.gh_list, &gl->gl_waiters1); + spin_unlock(&gl->gl_spin); + wait_on_holder(&gh); + gfs2_holder_uninit(&gh); } else { gl->gl_owner_pid = current->pid; gl->gl_ip = (unsigned long)__builtin_return_address(0); - clear_bit(HIF_WAIT, &gh.gh_iflags); - smp_mb(); - wake_up_bit(&gh.gh_iflags, HIF_WAIT); + spin_unlock(&gl->gl_spin); } - spin_unlock(&gl->gl_spin); - - wait_on_holder(&gh); - gfs2_holder_uninit(&gh); } /** @@ -691,7 +673,6 @@ static void gfs2_glmutex_unlock(struct gfs2_glock *gl) gl->gl_owner_pid = 0; gl->gl_ip = 0; run_queue(gl); - BUG_ON(!spin_is_locked(&gl->gl_spin)); spin_unlock(&gl->gl_spin); } @@ -722,7 +703,10 @@ static void handle_callback(struct gfs2_glock *gl, unsigned int state, } } else if (gl->gl_demote_state != LM_ST_UNLOCKED && gl->gl_demote_state != state) { - gl->gl_demote_state = LM_ST_UNLOCKED; + if (test_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags)) + gl->gl_waiters2 = 1; + else + gl->gl_demote_state = LM_ST_UNLOCKED; } spin_unlock(&gl->gl_spin); } @@ -943,8 +927,8 @@ static void gfs2_glock_drop_th(struct gfs2_glock *gl) const struct gfs2_glock_operations *glops = gl->gl_ops; unsigned int ret; - if (glops->go_drop_th) - glops->go_drop_th(gl); + if (glops->go_xmote_th) + glops->go_xmote_th(gl); gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); gfs2_assert_warn(sdp, list_empty(&gl->gl_holders)); @@ -1156,8 +1140,6 @@ restart: return -EIO; } - set_bit(HIF_PROMOTE, &gh->gh_iflags); - spin_lock(&gl->gl_spin); add_to_queue(gh); run_queue(gl); @@ -1248,12 +1230,11 @@ void gfs2_glock_dq(struct gfs2_holder *gh) list_del_init(&gh->gh_list); if (list_empty(&gl->gl_holders)) { - spin_unlock(&gl->gl_spin); - - if (glops->go_unlock) + if (glops->go_unlock) { + spin_unlock(&gl->gl_spin); glops->go_unlock(gh); - - spin_lock(&gl->gl_spin); + spin_lock(&gl->gl_spin); + } gl->gl_stamp = jiffies; } @@ -1910,8 +1891,6 @@ static int dump_glock(struct glock_iter *gi, struct gfs2_glock *gl) print_dbg(gi, " req_bh = %s\n", (gl->gl_req_bh) ? "yes" : "no"); print_dbg(gi, " lvb_count = %d\n", atomic_read(&gl->gl_lvb_count)); print_dbg(gi, " object = %s\n", (gl->gl_object) ? "yes" : "no"); - print_dbg(gi, " le = %s\n", - (list_empty(&gl->gl_le.le_list)) ? "no" : "yes"); print_dbg(gi, " reclaim = %s\n", (list_empty(&gl->gl_reclaim)) ? "no" : "yes"); if (gl->gl_aspace) diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 4670dcb2a877..c663b7a0f410 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -56,7 +56,7 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl) bd = list_entry(head->next, struct gfs2_bufdata, bd_ail_gl_list); bh = bd->bd_bh; - gfs2_remove_from_ail(NULL, bd); + gfs2_remove_from_ail(bd); bd->bd_bh = NULL; bh->b_private = NULL; bd->bd_blkno = bh->b_blocknr; @@ -86,15 +86,10 @@ static void gfs2_pte_inval(struct gfs2_glock *gl) if (!ip || !S_ISREG(inode->i_mode)) return; - if (!test_bit(GIF_PAGED, &ip->i_flags)) - return; - unmap_shared_mapping_range(inode->i_mapping, 0, 0); - if (test_bit(GIF_SW_PAGED, &ip->i_flags)) set_bit(GLF_DIRTY, &gl->gl_flags); - clear_bit(GIF_SW_PAGED, &ip->i_flags); } /** @@ -143,44 +138,34 @@ static void meta_go_inval(struct gfs2_glock *gl, int flags) static void inode_go_sync(struct gfs2_glock *gl) { struct gfs2_inode *ip = gl->gl_object; + struct address_space *metamapping = gl->gl_aspace->i_mapping; + int error; + + if (gl->gl_state != LM_ST_UNLOCKED) + gfs2_pte_inval(gl); + if (gl->gl_state != LM_ST_EXCLUSIVE) + return; if (ip && !S_ISREG(ip->i_inode.i_mode)) ip = NULL; if (test_bit(GLF_DIRTY, &gl->gl_flags)) { - if (ip && !gfs2_is_jdata(ip)) - filemap_fdatawrite(ip->i_inode.i_mapping); gfs2_log_flush(gl->gl_sbd, gl); - if (ip && gfs2_is_jdata(ip)) - filemap_fdatawrite(ip->i_inode.i_mapping); - gfs2_meta_sync(gl); + filemap_fdatawrite(metamapping); if (ip) { struct address_space *mapping = ip->i_inode.i_mapping; - int error = filemap_fdatawait(mapping); + filemap_fdatawrite(mapping); + error = filemap_fdatawait(mapping); mapping_set_error(mapping, error); } + error = filemap_fdatawait(metamapping); + mapping_set_error(metamapping, error); clear_bit(GLF_DIRTY, &gl->gl_flags); gfs2_ail_empty_gl(gl); } } /** - * inode_go_xmote_th - promote/demote a glock - * @gl: the glock - * @state: the requested state - * @flags: - * - */ - -static void inode_go_xmote_th(struct gfs2_glock *gl) -{ - if (gl->gl_state != LM_ST_UNLOCKED) - gfs2_pte_inval(gl); - if (gl->gl_state == LM_ST_EXCLUSIVE) - inode_go_sync(gl); -} - -/** * inode_go_xmote_bh - After promoting/demoting a glock * @gl: the glock * @@ -201,22 +186,6 @@ static void inode_go_xmote_bh(struct gfs2_glock *gl) } /** - * inode_go_drop_th - unlock a glock - * @gl: the glock - * - * Invoked from rq_demote(). - * Another node needs the lock in EXCLUSIVE mode, or lock (unused for too long) - * is being purged from our node's glock cache; we're dropping lock. - */ - -static void inode_go_drop_th(struct gfs2_glock *gl) -{ - gfs2_pte_inval(gl); - if (gl->gl_state == LM_ST_EXCLUSIVE) - inode_go_sync(gl); -} - -/** * inode_go_inval - prepare a inode glock to be released * @gl: the glock * @flags: @@ -234,10 +203,8 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags) set_bit(GIF_INVALID, &ip->i_flags); } - if (ip && S_ISREG(ip->i_inode.i_mode)) { + if (ip && S_ISREG(ip->i_inode.i_mode)) truncate_inode_pages(ip->i_inode.i_mapping, 0); - clear_bit(GIF_PAGED, &ip->i_flags); - } } /** @@ -294,23 +261,6 @@ static int inode_go_lock(struct gfs2_holder *gh) } /** - * inode_go_unlock - operation done before an inode lock is unlocked by a - * process - * @gl: the glock - * @flags: - * - */ - -static void inode_go_unlock(struct gfs2_holder *gh) -{ - struct gfs2_glock *gl = gh->gh_gl; - struct gfs2_inode *ip = gl->gl_object; - - if (ip) - gfs2_meta_cache_flush(ip); -} - -/** * rgrp_go_demote_ok - Check to see if it's ok to unlock a RG's glock * @gl: the glock * @@ -350,14 +300,14 @@ static void rgrp_go_unlock(struct gfs2_holder *gh) } /** - * trans_go_xmote_th - promote/demote the transaction glock + * trans_go_sync - promote/demote the transaction glock * @gl: the glock * @state: the requested state * @flags: * */ -static void trans_go_xmote_th(struct gfs2_glock *gl) +static void trans_go_sync(struct gfs2_glock *gl) { struct gfs2_sbd *sdp = gl->gl_sbd; @@ -384,7 +334,6 @@ static void trans_go_xmote_bh(struct gfs2_glock *gl) if (gl->gl_state != LM_ST_UNLOCKED && test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) { - gfs2_meta_cache_flush(GFS2_I(sdp->sd_jdesc->jd_inode)); j_gl->gl_ops->go_inval(j_gl, DIO_METADATA); error = gfs2_find_jhead(sdp->sd_jdesc, &head); @@ -402,24 +351,6 @@ static void trans_go_xmote_bh(struct gfs2_glock *gl) } /** - * trans_go_drop_th - unlock the transaction glock - * @gl: the glock - * - * We want to sync the device even with localcaching. Remember - * that localcaching journal replay only marks buffers dirty. - */ - -static void trans_go_drop_th(struct gfs2_glock *gl) -{ - struct gfs2_sbd *sdp = gl->gl_sbd; - - if (test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) { - gfs2_meta_syncfs(sdp); - gfs2_log_shutdown(sdp); - } -} - -/** * quota_go_demote_ok - Check to see if it's ok to unlock a quota glock * @gl: the glock * @@ -433,25 +364,21 @@ static int quota_go_demote_ok(struct gfs2_glock *gl) const struct gfs2_glock_operations gfs2_meta_glops = { .go_xmote_th = meta_go_sync, - .go_drop_th = meta_go_sync, .go_type = LM_TYPE_META, }; const struct gfs2_glock_operations gfs2_inode_glops = { - .go_xmote_th = inode_go_xmote_th, + .go_xmote_th = inode_go_sync, .go_xmote_bh = inode_go_xmote_bh, - .go_drop_th = inode_go_drop_th, .go_inval = inode_go_inval, .go_demote_ok = inode_go_demote_ok, .go_lock = inode_go_lock, - .go_unlock = inode_go_unlock, .go_type = LM_TYPE_INODE, .go_min_hold_time = HZ / 10, }; const struct gfs2_glock_operations gfs2_rgrp_glops = { .go_xmote_th = meta_go_sync, - .go_drop_th = meta_go_sync, .go_inval = meta_go_inval, .go_demote_ok = rgrp_go_demote_ok, .go_lock = rgrp_go_lock, @@ -461,9 +388,8 @@ const struct gfs2_glock_operations gfs2_rgrp_glops = { }; const struct gfs2_glock_operations gfs2_trans_glops = { - .go_xmote_th = trans_go_xmote_th, + .go_xmote_th = trans_go_sync, .go_xmote_bh = trans_go_xmote_bh, - .go_drop_th = trans_go_drop_th, .go_type = LM_TYPE_NONDISK, }; diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index eaddfb5a8e6f..513aaf0dc0ab 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -1,6 +1,6 @@ /* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions @@ -131,7 +131,6 @@ struct gfs2_bufdata { struct gfs2_glock_operations { void (*go_xmote_th) (struct gfs2_glock *gl); void (*go_xmote_bh) (struct gfs2_glock *gl); - void (*go_drop_th) (struct gfs2_glock *gl); void (*go_inval) (struct gfs2_glock *gl, int flags); int (*go_demote_ok) (struct gfs2_glock *gl); int (*go_lock) (struct gfs2_holder *gh); @@ -141,10 +140,6 @@ struct gfs2_glock_operations { }; enum { - /* Actions */ - HIF_MUTEX = 0, - HIF_PROMOTE = 1, - /* States */ HIF_HOLDER = 6, HIF_FIRST = 7, @@ -171,6 +166,8 @@ enum { GLF_DEMOTE = 3, GLF_PENDING_DEMOTE = 4, GLF_DIRTY = 5, + GLF_DEMOTE_IN_PROGRESS = 6, + GLF_LFLUSH = 7, }; struct gfs2_glock { @@ -190,6 +187,7 @@ struct gfs2_glock { struct list_head gl_holders; struct list_head gl_waiters1; /* HIF_MUTEX */ struct list_head gl_waiters3; /* HIF_PROMOTE */ + int gl_waiters2; /* GIF_DEMOTE */ const struct gfs2_glock_operations *gl_ops; @@ -210,7 +208,6 @@ struct gfs2_glock { struct gfs2_sbd *gl_sbd; struct inode *gl_aspace; - struct gfs2_log_element gl_le; struct list_head gl_ail_list; atomic_t gl_ail_count; struct delayed_work gl_work; @@ -239,7 +236,6 @@ struct gfs2_alloc { enum { GIF_INVALID = 0, GIF_QD_LOCKED = 1, - GIF_PAGED = 2, GIF_SW_PAGED = 3, }; @@ -268,14 +264,10 @@ struct gfs2_inode { struct gfs2_glock *i_gl; /* Move into i_gh? */ struct gfs2_holder i_iopen_gh; struct gfs2_holder i_gh; /* for prepare/commit_write only */ - struct gfs2_alloc i_alloc; + struct gfs2_alloc *i_alloc; u64 i_last_rg_alloc; - spinlock_t i_spin; struct rw_semaphore i_rw_mutex; - unsigned long i_last_pfault; - - struct buffer_head *i_cache[GFS2_MAX_META_HEIGHT]; }; /* @@ -287,19 +279,12 @@ static inline struct gfs2_inode *GFS2_I(struct inode *inode) return container_of(inode, struct gfs2_inode, i_inode); } -/* To be removed? */ -static inline struct gfs2_sbd *GFS2_SB(struct inode *inode) +static inline struct gfs2_sbd *GFS2_SB(const struct inode *inode) { return inode->i_sb->s_fs_info; } -enum { - GFF_DID_DIRECT_ALLOC = 0, - GFF_EXLOCK = 1, -}; - struct gfs2_file { - unsigned long f_flags; /* GFF_... */ struct mutex f_fl_mutex; struct gfs2_holder f_fl_gh; }; @@ -373,8 +358,17 @@ struct gfs2_ail { u64 ai_sync_gen; }; +struct gfs2_journal_extent { + struct list_head extent_list; + + unsigned int lblock; /* First logical block */ + u64 dblock; /* First disk block */ + u64 blocks; +}; + struct gfs2_jdesc { struct list_head jd_list; + struct list_head extent_list; struct inode *jd_inode; unsigned int jd_jid; @@ -421,13 +415,9 @@ struct gfs2_args { struct gfs2_tune { spinlock_t gt_spin; - unsigned int gt_ilimit; - unsigned int gt_ilimit_tries; - unsigned int gt_ilimit_min; unsigned int gt_demote_secs; /* Cache retention for unheld glock */ unsigned int gt_incore_log_blocks; unsigned int gt_log_flush_secs; - unsigned int gt_jindex_refresh_secs; /* Check for new journal index */ unsigned int gt_recoverd_secs; unsigned int gt_logd_secs; @@ -443,10 +433,8 @@ struct gfs2_tune { unsigned int gt_new_files_jdata; unsigned int gt_new_files_directio; unsigned int gt_max_readahead; /* Max bytes to read-ahead from disk */ - unsigned int gt_lockdump_size; unsigned int gt_stall_secs; /* Detects trouble! */ unsigned int gt_complain_secs; - unsigned int gt_reclaim_limit; /* Max num of glocks in reclaim list */ unsigned int gt_statfs_quantum; unsigned int gt_statfs_slow; }; @@ -539,7 +527,6 @@ struct gfs2_sbd { /* StatFS stuff */ spinlock_t sd_statfs_spin; - struct mutex sd_statfs_mutex; struct gfs2_statfs_change_host sd_statfs_master; struct gfs2_statfs_change_host sd_statfs_local; unsigned long sd_statfs_sync_time; @@ -602,20 +589,18 @@ struct gfs2_sbd { unsigned int sd_log_commited_databuf; unsigned int sd_log_commited_revoke; - unsigned int sd_log_num_gl; unsigned int sd_log_num_buf; unsigned int sd_log_num_revoke; unsigned int sd_log_num_rg; unsigned int sd_log_num_databuf; - struct list_head sd_log_le_gl; struct list_head sd_log_le_buf; struct list_head sd_log_le_revoke; struct list_head sd_log_le_rg; struct list_head sd_log_le_databuf; struct list_head sd_log_le_ordered; - unsigned int sd_log_blks_free; + atomic_t sd_log_blks_free; struct mutex sd_log_reserve_mutex; u64 sd_log_sequence; diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 5f6dc32946cd..728d3169e7bd 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -31,7 +31,6 @@ #include "log.h" #include "meta_io.h" #include "ops_address.h" -#include "ops_file.h" #include "ops_inode.h" #include "quota.h" #include "rgrp.h" @@ -132,15 +131,21 @@ static struct inode *gfs2_iget_skip(struct super_block *sb, void gfs2_set_iop(struct inode *inode) { + struct gfs2_sbd *sdp = GFS2_SB(inode); umode_t mode = inode->i_mode; if (S_ISREG(mode)) { inode->i_op = &gfs2_file_iops; - inode->i_fop = &gfs2_file_fops; - inode->i_mapping->a_ops = &gfs2_file_aops; + if (sdp->sd_args.ar_localflocks) + inode->i_fop = &gfs2_file_fops_nolock; + else + inode->i_fop = &gfs2_file_fops; } else if (S_ISDIR(mode)) { inode->i_op = &gfs2_dir_iops; - inode->i_fop = &gfs2_dir_fops; + if (sdp->sd_args.ar_localflocks) + inode->i_fop = &gfs2_dir_fops_nolock; + else + inode->i_fop = &gfs2_dir_fops; } else if (S_ISLNK(mode)) { inode->i_op = &gfs2_symlink_iops; } else { @@ -291,12 +296,10 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) di->di_entries = be32_to_cpu(str->di_entries); di->di_eattr = be64_to_cpu(str->di_eattr); - return 0; -} + if (S_ISREG(ip->i_inode.i_mode)) + gfs2_set_aops(&ip->i_inode); -static void gfs2_inode_bh(struct gfs2_inode *ip, struct buffer_head *bh) -{ - ip->i_cache[0] = bh; + return 0; } /** @@ -366,7 +369,8 @@ int gfs2_dinode_dealloc(struct gfs2_inode *ip) if (error) goto out_rg_gunlock; - gfs2_trans_add_gl(ip->i_gl); + set_bit(GLF_DIRTY, &ip->i_gl->gl_flags); + set_bit(GLF_LFLUSH, &ip->i_gl->gl_flags); gfs2_free_di(rgd, ip); @@ -707,9 +711,10 @@ static int alloc_dinode(struct gfs2_inode *dip, u64 *no_addr, u64 *generation) struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); int error; - gfs2_alloc_get(dip); + if (gfs2_alloc_get(dip) == NULL) + return -ENOMEM; - dip->i_alloc.al_requested = RES_DINODE; + dip->i_alloc->al_requested = RES_DINODE; error = gfs2_inplace_reserve(dip); if (error) goto out; @@ -855,7 +860,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name, error = alloc_required = gfs2_diradd_alloc_required(&dip->i_inode, name); if (alloc_required < 0) - goto fail; + goto fail_quota_locks; if (alloc_required) { error = gfs2_quota_check(dip, dip->i_inode.i_uid, dip->i_inode.i_gid); if (error) @@ -896,7 +901,7 @@ fail_end_trans: gfs2_trans_end(sdp); fail_ipreserv: - if (dip->i_alloc.al_rgd) + if (dip->i_alloc->al_rgd) gfs2_inplace_release(dip); fail_quota_locks: @@ -966,7 +971,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 }; int error; u64 generation; - struct buffer_head *bh=NULL; + struct buffer_head *bh = NULL; if (!name->len || name->len > GFS2_FNAMESIZE) return ERR_PTR(-ENAMETOOLONG); @@ -1003,8 +1008,6 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, if (IS_ERR(inode)) goto fail_gunlock2; - gfs2_inode_bh(GFS2_I(inode), bh); - error = gfs2_inode_refresh(GFS2_I(inode)); if (error) goto fail_gunlock2; @@ -1021,6 +1024,8 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, if (error) goto fail_gunlock2; + if (bh) + brelse(bh); if (!inode) return ERR_PTR(-ENOMEM); return inode; @@ -1032,6 +1037,8 @@ fail_gunlock2: fail_gunlock: gfs2_glock_dq(ghs); fail: + if (bh) + brelse(bh); return ERR_PTR(error); } diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index 351ac87ab384..d44650662615 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -20,6 +20,18 @@ static inline int gfs2_is_jdata(const struct gfs2_inode *ip) return ip->i_di.di_flags & GFS2_DIF_JDATA; } +static inline int gfs2_is_writeback(const struct gfs2_inode *ip) +{ + const struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); + return (sdp->sd_args.ar_data == GFS2_DATA_WRITEBACK) && !gfs2_is_jdata(ip); +} + +static inline int gfs2_is_ordered(const struct gfs2_inode *ip) +{ + const struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); + return (sdp->sd_args.ar_data == GFS2_DATA_ORDERED) && !gfs2_is_jdata(ip); +} + static inline int gfs2_is_dir(const struct gfs2_inode *ip) { return S_ISDIR(ip->i_inode.i_mode); diff --git a/fs/gfs2/locking/dlm/mount.c b/fs/gfs2/locking/dlm/mount.c index 41c5b04caaba..f2efff424224 100644 --- a/fs/gfs2/locking/dlm/mount.c +++ b/fs/gfs2/locking/dlm/mount.c @@ -67,6 +67,11 @@ static int make_args(struct gdlm_ls *ls, char *data_arg, int *nodir) memset(data, 0, 256); strncpy(data, data_arg, 255); + if (!strlen(data)) { + log_error("no mount options, (u)mount helpers not installed"); + return -EINVAL; + } + for (options = data; (x = strsep(&options, ":")); ) { if (!*x) continue; diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c index 1f7b038530b4..2ebd374b3143 100644 --- a/fs/gfs2/locking/dlm/plock.c +++ b/fs/gfs2/locking/dlm/plock.c @@ -89,15 +89,19 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name, op->info.number = name->ln_number; op->info.start = fl->fl_start; op->info.end = fl->fl_end; - op->info.owner = (__u64)(long) fl->fl_owner; if (fl->fl_lmops && fl->fl_lmops->fl_grant) { + /* fl_owner is lockd which doesn't distinguish + processes on the nfs client */ + op->info.owner = (__u64) fl->fl_pid; xop->callback = fl->fl_lmops->fl_grant; locks_init_lock(&xop->flc); locks_copy_lock(&xop->flc, fl); xop->fl = fl; xop->file = file; - } else + } else { + op->info.owner = (__u64)(long) fl->fl_owner; xop->callback = NULL; + } send_op(op); @@ -203,7 +207,10 @@ int gdlm_punlock(void *lockspace, struct lm_lockname *name, op->info.number = name->ln_number; op->info.start = fl->fl_start; op->info.end = fl->fl_end; - op->info.owner = (__u64)(long) fl->fl_owner; + if (fl->fl_lmops && fl->fl_lmops->fl_grant) + op->info.owner = (__u64) fl->fl_pid; + else + op->info.owner = (__u64)(long) fl->fl_owner; send_op(op); wait_event(recv_wq, (op->done != 0)); @@ -242,7 +249,10 @@ int gdlm_plock_get(void *lockspace, struct lm_lockname *name, op->info.number = name->ln_number; op->info.start = fl->fl_start; op->info.end = fl->fl_end; - op->info.owner = (__u64)(long) fl->fl_owner; + if (fl->fl_lmops && fl->fl_lmops->fl_grant) + op->info.owner = (__u64) fl->fl_pid; + else + op->info.owner = (__u64)(long) fl->fl_owner; send_op(op); wait_event(recv_wq, (op->done != 0)); diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c index ae9e6a25fe2b..a87b09839761 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/locking/dlm/thread.c b/fs/gfs2/locking/dlm/thread.c index bd938f06481d..521694fc19d6 100644 --- a/fs/gfs2/locking/dlm/thread.c +++ b/fs/gfs2/locking/dlm/thread.c @@ -273,18 +273,13 @@ static int gdlm_thread(void *data, int blist) struct gdlm_ls *ls = (struct gdlm_ls *) data; struct gdlm_lock *lp = NULL; uint8_t complete, blocking, submit, drop; - DECLARE_WAITQUEUE(wait, current); /* Only thread1 is allowed to do blocking callbacks since gfs may wait for a completion callback within a blocking cb. */ while (!kthread_should_stop()) { - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&ls->thread_wait, &wait); - if (no_work(ls, blist)) - schedule(); - remove_wait_queue(&ls->thread_wait, &wait); - set_current_state(TASK_RUNNING); + wait_event_interruptible(ls->thread_wait, + !no_work(ls, blist) || kthread_should_stop()); complete = blocking = submit = drop = 0; diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 7df702473252..161ab6f2058e 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -1,6 +1,6 @@ /* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions @@ -16,6 +16,8 @@ #include <linux/crc32.h> #include <linux/lm_interface.h> #include <linux/delay.h> +#include <linux/kthread.h> +#include <linux/freezer.h> #include "gfs2.h" #include "incore.h" @@ -68,14 +70,12 @@ unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct, * */ -void gfs2_remove_from_ail(struct address_space *mapping, struct gfs2_bufdata *bd) +void gfs2_remove_from_ail(struct gfs2_bufdata *bd) { bd->bd_ail = NULL; list_del_init(&bd->bd_ail_st_list); list_del_init(&bd->bd_ail_gl_list); atomic_dec(&bd->bd_gl->gl_ail_count); - if (mapping) - gfs2_meta_cache_flush(GFS2_I(mapping->host)); brelse(bd->bd_bh); } @@ -92,8 +92,6 @@ static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) struct buffer_head *bh; int retry; - BUG_ON(!spin_is_locked(&sdp->sd_log_lock)); - do { retry = 0; @@ -210,7 +208,7 @@ static void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags) gfs2_log_unlock(sdp); } -int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags) +static int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags) { struct gfs2_ail *ai, *s; int ret; @@ -248,7 +246,7 @@ static void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) bd = list_entry(head->prev, struct gfs2_bufdata, bd_ail_st_list); gfs2_assert(sdp, bd->bd_ail == ai); - gfs2_remove_from_ail(bd->bd_bh->b_page->mapping, bd); + gfs2_remove_from_ail(bd); } } @@ -303,7 +301,7 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks) mutex_lock(&sdp->sd_log_reserve_mutex); gfs2_log_lock(sdp); - while(sdp->sd_log_blks_free <= (blks + reserved_blks)) { + while(atomic_read(&sdp->sd_log_blks_free) <= (blks + reserved_blks)) { gfs2_log_unlock(sdp); gfs2_ail1_empty(sdp, 0); gfs2_log_flush(sdp, NULL); @@ -312,7 +310,7 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks) gfs2_ail1_start(sdp, 0); gfs2_log_lock(sdp); } - sdp->sd_log_blks_free -= blks; + atomic_sub(blks, &sdp->sd_log_blks_free); gfs2_log_unlock(sdp); mutex_unlock(&sdp->sd_log_reserve_mutex); @@ -332,27 +330,23 @@ void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks) { gfs2_log_lock(sdp); - sdp->sd_log_blks_free += blks; + atomic_add(blks, &sdp->sd_log_blks_free); gfs2_assert_withdraw(sdp, - sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks); + atomic_read(&sdp->sd_log_blks_free) <= sdp->sd_jdesc->jd_blocks); gfs2_log_unlock(sdp); up_read(&sdp->sd_log_flush_lock); } static u64 log_bmap(struct gfs2_sbd *sdp, unsigned int lbn) { - struct inode *inode = sdp->sd_jdesc->jd_inode; - int error; - struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 }; - - bh_map.b_size = 1 << inode->i_blkbits; - error = gfs2_block_map(inode, lbn, 0, &bh_map); - if (error || !bh_map.b_blocknr) - printk(KERN_INFO "error=%d, dbn=%llu lbn=%u", error, - (unsigned long long)bh_map.b_blocknr, lbn); - gfs2_assert_withdraw(sdp, !error && bh_map.b_blocknr); - - return bh_map.b_blocknr; + struct gfs2_journal_extent *je; + + list_for_each_entry(je, &sdp->sd_jdesc->extent_list, extent_list) { + if (lbn >= je->lblock && lbn < je->lblock + je->blocks) + return je->dblock + lbn - je->lblock; + } + + return -1; } /** @@ -561,8 +555,8 @@ static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail) ail2_empty(sdp, new_tail); gfs2_log_lock(sdp); - sdp->sd_log_blks_free += dist; - gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks); + atomic_add(dist, &sdp->sd_log_blks_free); + gfs2_assert_withdraw(sdp, atomic_read(&sdp->sd_log_blks_free) <= sdp->sd_jdesc->jd_blocks); gfs2_log_unlock(sdp); sdp->sd_log_tail = new_tail; @@ -652,7 +646,7 @@ static void gfs2_ordered_write(struct gfs2_sbd *sdp) get_bh(bh); gfs2_log_unlock(sdp); lock_buffer(bh); - if (test_clear_buffer_dirty(bh)) { + if (buffer_mapped(bh) && test_clear_buffer_dirty(bh)) { bh->b_end_io = end_buffer_write_sync; submit_bh(WRITE, bh); } else { @@ -694,20 +688,16 @@ static void gfs2_ordered_wait(struct gfs2_sbd *sdp) * */ -void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) +void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) { struct gfs2_ail *ai; down_write(&sdp->sd_log_flush_lock); - if (gl) { - gfs2_log_lock(sdp); - if (list_empty(&gl->gl_le.le_list)) { - gfs2_log_unlock(sdp); - up_write(&sdp->sd_log_flush_lock); - return; - } - gfs2_log_unlock(sdp); + /* Log might have been flushed while we waited for the flush lock */ + if (gl && !test_bit(GLF_LFLUSH, &gl->gl_flags)) { + up_write(&sdp->sd_log_flush_lock); + return; } ai = kzalloc(sizeof(struct gfs2_ail), GFP_NOFS | __GFP_NOFAIL); @@ -739,7 +729,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) log_flush_commit(sdp); else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){ gfs2_log_lock(sdp); - sdp->sd_log_blks_free--; /* Adjust for unreserved buffer */ + atomic_dec(&sdp->sd_log_blks_free); /* Adjust for unreserved buffer */ gfs2_log_unlock(sdp); log_write_header(sdp, 0, PULL); } @@ -767,7 +757,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr) { unsigned int reserved; - unsigned int old; + unsigned int unused; gfs2_log_lock(sdp); @@ -779,14 +769,11 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr) sdp->sd_log_commited_revoke += tr->tr_num_revoke - tr->tr_num_revoke_rm; gfs2_assert_withdraw(sdp, ((int)sdp->sd_log_commited_revoke) >= 0); reserved = calc_reserved(sdp); - old = sdp->sd_log_blks_free; - sdp->sd_log_blks_free += tr->tr_reserved - - (reserved - sdp->sd_log_blks_reserved); - - gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free >= old); - gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free <= + unused = sdp->sd_log_blks_reserved - reserved + tr->tr_reserved; + gfs2_assert_withdraw(sdp, unused >= 0); + atomic_add(unused, &sdp->sd_log_blks_free); + gfs2_assert_withdraw(sdp, atomic_read(&sdp->sd_log_blks_free) <= sdp->sd_jdesc->jd_blocks); - sdp->sd_log_blks_reserved = reserved; gfs2_log_unlock(sdp); @@ -825,7 +812,6 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp) down_write(&sdp->sd_log_flush_lock); gfs2_assert_withdraw(sdp, !sdp->sd_log_blks_reserved); - gfs2_assert_withdraw(sdp, !sdp->sd_log_num_gl); gfs2_assert_withdraw(sdp, !sdp->sd_log_num_buf); gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke); gfs2_assert_withdraw(sdp, !sdp->sd_log_num_rg); @@ -838,7 +824,7 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp) log_write_header(sdp, GFS2_LOG_HEAD_UNMOUNT, (sdp->sd_log_tail == current_tail(sdp)) ? 0 : PULL); - gfs2_assert_warn(sdp, sdp->sd_log_blks_free == sdp->sd_jdesc->jd_blocks); + gfs2_assert_warn(sdp, atomic_read(&sdp->sd_log_blks_free) == sdp->sd_jdesc->jd_blocks); gfs2_assert_warn(sdp, sdp->sd_log_head == sdp->sd_log_tail); gfs2_assert_warn(sdp, list_empty(&sdp->sd_ail2_list)); @@ -866,3 +852,42 @@ void gfs2_meta_syncfs(struct gfs2_sbd *sdp) } } + +/** + * gfs2_logd - Update log tail as Active Items get flushed to in-place blocks + * @sdp: Pointer to GFS2 superblock + * + * Also, periodically check to make sure that we're using the most recent + * journal index. + */ + +int gfs2_logd(void *data) +{ + struct gfs2_sbd *sdp = data; + unsigned long t; + int need_flush; + + while (!kthread_should_stop()) { + /* Advance the log tail */ + + t = sdp->sd_log_flush_time + + gfs2_tune_get(sdp, gt_log_flush_secs) * HZ; + + gfs2_ail1_empty(sdp, DIO_ALL); + gfs2_log_lock(sdp); + need_flush = sdp->sd_log_num_buf > gfs2_tune_get(sdp, gt_incore_log_blocks); + gfs2_log_unlock(sdp); + if (need_flush || time_after_eq(jiffies, t)) { + gfs2_log_flush(sdp, NULL); + sdp->sd_log_flush_time = jiffies; + } + + t = gfs2_tune_get(sdp, gt_logd_secs) * HZ; + if (freezing(current)) + refrigerator(); + schedule_timeout_interruptible(t); + } + + return 0; +} + diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h index dae282400627..771152816508 100644 --- a/fs/gfs2/log.h +++ b/fs/gfs2/log.h @@ -48,8 +48,6 @@ static inline void gfs2_log_pointers_init(struct gfs2_sbd *sdp, unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct, unsigned int ssize); -int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags); - int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks); void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks); void gfs2_log_incr_head(struct gfs2_sbd *sdp); @@ -57,11 +55,19 @@ void gfs2_log_incr_head(struct gfs2_sbd *sdp); struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp); struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp, struct buffer_head *real); -void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl); +void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl); + +static inline void gfs2_log_flush(struct gfs2_sbd *sbd, struct gfs2_glock *gl) +{ + if (!gl || test_bit(GLF_LFLUSH, &gl->gl_flags)) + __gfs2_log_flush(sbd, gl); +} + void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans); -void gfs2_remove_from_ail(struct address_space *mapping, struct gfs2_bufdata *bd); +void gfs2_remove_from_ail(struct gfs2_bufdata *bd); void gfs2_log_shutdown(struct gfs2_sbd *sdp); void gfs2_meta_syncfs(struct gfs2_sbd *sdp); +int gfs2_logd(void *data); #endif /* __LOG_DOT_H__ */ diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 6c27cea761c6..fae59d69d01a 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -87,6 +87,7 @@ static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh, } bd->bd_ail = ai; list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list); + clear_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags); gfs2_log_unlock(sdp); unlock_buffer(bh); } @@ -124,49 +125,6 @@ static struct buffer_head *gfs2_get_log_desc(struct gfs2_sbd *sdp, u32 ld_type) return bh; } -static void __glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) -{ - struct gfs2_glock *gl; - struct gfs2_trans *tr = current->journal_info; - - tr->tr_touched = 1; - - gl = container_of(le, struct gfs2_glock, gl_le); - if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(gl))) - return; - - if (!list_empty(&le->le_list)) - return; - - gfs2_glock_hold(gl); - set_bit(GLF_DIRTY, &gl->gl_flags); - sdp->sd_log_num_gl++; - list_add(&le->le_list, &sdp->sd_log_le_gl); -} - -static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) -{ - gfs2_log_lock(sdp); - __glock_lo_add(sdp, le); - gfs2_log_unlock(sdp); -} - -static void glock_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) -{ - struct list_head *head = &sdp->sd_log_le_gl; - struct gfs2_glock *gl; - - while (!list_empty(head)) { - gl = list_entry(head->next, struct gfs2_glock, gl_le.le_list); - list_del_init(&gl->gl_le.le_list); - sdp->sd_log_num_gl--; - - gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(gl)); - gfs2_glock_put(gl); - } - gfs2_assert_warn(sdp, !sdp->sd_log_num_gl); -} - static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) { struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le); @@ -182,7 +140,8 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) list_add(&bd->bd_list_tr, &tr->tr_list_buf); if (!list_empty(&le->le_list)) goto out; - __glock_lo_add(sdp, &bd->bd_gl->gl_le); + set_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags); + set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags); gfs2_meta_check(sdp, bd->bd_bh); gfs2_pin(sdp, bd->bd_bh); sdp->sd_log_num_buf++; @@ -556,17 +515,20 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) lock_buffer(bd->bd_bh); gfs2_log_lock(sdp); - if (!list_empty(&bd->bd_list_tr)) - goto out; - tr->tr_touched = 1; - if (gfs2_is_jdata(ip)) { - tr->tr_num_buf++; - list_add(&bd->bd_list_tr, &tr->tr_list_buf); + if (tr) { + if (!list_empty(&bd->bd_list_tr)) + goto out; + tr->tr_touched = 1; + if (gfs2_is_jdata(ip)) { + tr->tr_num_buf++; + list_add(&bd->bd_list_tr, &tr->tr_list_buf); + } } if (!list_empty(&le->le_list)) goto out; - __glock_lo_add(sdp, &bd->bd_gl->gl_le); + set_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags); + set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags); if (gfs2_is_jdata(ip)) { gfs2_pin(sdp, bd->bd_bh); tr->tr_num_databuf_new++; @@ -773,12 +735,6 @@ static void databuf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) } -const struct gfs2_log_operations gfs2_glock_lops = { - .lo_add = glock_lo_add, - .lo_after_commit = glock_lo_after_commit, - .lo_name = "glock", -}; - const struct gfs2_log_operations gfs2_buf_lops = { .lo_add = buf_lo_add, .lo_incore_commit = buf_lo_incore_commit, @@ -816,7 +772,6 @@ const struct gfs2_log_operations gfs2_databuf_lops = { }; const struct gfs2_log_operations *gfs2_log_ops[] = { - &gfs2_glock_lops, &gfs2_databuf_lops, &gfs2_buf_lops, &gfs2_rg_lops, diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index 7ecfe0d3a491..9c7765c12d62 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -29,9 +29,8 @@ static void gfs2_init_inode_once(struct kmem_cache *cachep, void *foo) struct gfs2_inode *ip = foo; inode_init_once(&ip->i_inode); - spin_lock_init(&ip->i_spin); init_rwsem(&ip->i_rw_mutex); - memset(ip->i_cache, 0, sizeof(ip->i_cache)); + ip->i_alloc = NULL; } static void gfs2_init_glock_once(struct kmem_cache *cachep, void *foo) diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 4da423985e4f..85aea27b4a86 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -50,6 +50,7 @@ static int gfs2_aspace_writepage(struct page *page, static const struct address_space_operations aspace_aops = { .writepage = gfs2_aspace_writepage, .releasepage = gfs2_releasepage, + .sync_page = block_sync_page, }; /** @@ -221,13 +222,14 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags, struct buffer_head **bhp) { *bhp = getbuf(gl, blkno, CREATE); - if (!buffer_uptodate(*bhp)) + if (!buffer_uptodate(*bhp)) { ll_rw_block(READ_META, 1, bhp); - if (flags & DIO_WAIT) { - int error = gfs2_meta_wait(gl->gl_sbd, *bhp); - if (error) { - brelse(*bhp); - return error; + if (flags & DIO_WAIT) { + int error = gfs2_meta_wait(gl->gl_sbd, *bhp); + if (error) { + brelse(*bhp); + return error; + } } } @@ -282,7 +284,7 @@ void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, return; } - bd = kmem_cache_zalloc(gfs2_bufdata_cachep, GFP_NOFS | __GFP_NOFAIL), + bd = kmem_cache_zalloc(gfs2_bufdata_cachep, GFP_NOFS | __GFP_NOFAIL); bd->bd_bh = bh; bd->bd_gl = gl; @@ -317,7 +319,7 @@ void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr, int } if (bd) { if (bd->bd_ail) { - gfs2_remove_from_ail(NULL, bd); + gfs2_remove_from_ail(bd); bh->b_private = NULL; bd->bd_bh = NULL; bd->bd_blkno = bh->b_blocknr; @@ -358,32 +360,6 @@ void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen) } /** - * gfs2_meta_cache_flush - get rid of any references on buffers for this inode - * @ip: The GFS2 inode - * - * This releases buffers that are in the most-recently-used array of - * blocks used for indirect block addressing for this inode. - */ - -void gfs2_meta_cache_flush(struct gfs2_inode *ip) -{ - struct buffer_head **bh_slot; - unsigned int x; - - spin_lock(&ip->i_spin); - - for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) { - bh_slot = &ip->i_cache[x]; - if (*bh_slot) { - brelse(*bh_slot); - *bh_slot = NULL; - } - } - - spin_unlock(&ip->i_spin); -} - -/** * gfs2_meta_indirect_buffer - Get a metadata buffer * @ip: The GFS2 inode * @height: The level of this buf in the metadata (indir addr) tree (if any) @@ -391,8 +367,6 @@ void gfs2_meta_cache_flush(struct gfs2_inode *ip) * @new: Non-zero if we may create a new buffer * @bhp: the buffer is returned here * - * Try to use the gfs2_inode's MRU metadata tree cache. - * * Returns: errno */ @@ -401,58 +375,25 @@ int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num, { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_glock *gl = ip->i_gl; - struct buffer_head *bh = NULL, **bh_slot = ip->i_cache + height; - int in_cache = 0; - - BUG_ON(!gl); - BUG_ON(!sdp); - - spin_lock(&ip->i_spin); - if (*bh_slot && (*bh_slot)->b_blocknr == num) { - bh = *bh_slot; - get_bh(bh); - in_cache = 1; - } - spin_unlock(&ip->i_spin); - - if (!bh) - bh = getbuf(gl, num, CREATE); - - if (!bh) - return -ENOBUFS; + struct buffer_head *bh; + int ret = 0; if (new) { - if (gfs2_assert_warn(sdp, height)) - goto err; - meta_prep_new(bh); + BUG_ON(height == 0); + bh = gfs2_meta_new(gl, num); gfs2_trans_add_bh(ip->i_gl, bh, 1); gfs2_metatype_set(bh, GFS2_METATYPE_IN, GFS2_FORMAT_IN); gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header)); } else { u32 mtype = height ? GFS2_METATYPE_IN : GFS2_METATYPE_DI; - if (!buffer_uptodate(bh)) { - ll_rw_block(READ_META, 1, &bh); - if (gfs2_meta_wait(sdp, bh)) - goto err; + ret = gfs2_meta_read(gl, num, DIO_WAIT, &bh); + if (ret == 0 && gfs2_metatype_check(sdp, bh, mtype)) { + brelse(bh); + ret = -EIO; } - if (gfs2_metatype_check(sdp, bh, mtype)) - goto err; - } - - if (!in_cache) { - spin_lock(&ip->i_spin); - if (*bh_slot) - brelse(*bh_slot); - *bh_slot = bh; - get_bh(bh); - spin_unlock(&ip->i_spin); } - *bhp = bh; - return 0; -err: - brelse(bh); - return -EIO; + return ret; } /** diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h index b7048222ebb4..73e3b1c76fe1 100644 --- a/fs/gfs2/meta_io.h +++ b/fs/gfs2/meta_io.h @@ -56,7 +56,6 @@ void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr, void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen); -void gfs2_meta_cache_flush(struct gfs2_inode *ip); int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num, int new, struct buffer_head **bhp); diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 9679f8b9870d..38dbe99a30ed 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -20,6 +20,8 @@ #include <linux/swap.h> #include <linux/gfs2_ondisk.h> #include <linux/lm_interface.h> +#include <linux/backing-dev.h> +#include <linux/pagevec.h> #include "gfs2.h" #include "incore.h" @@ -32,7 +34,6 @@ #include "quota.h" #include "trans.h" #include "rgrp.h" -#include "ops_file.h" #include "super.h" #include "util.h" #include "glops.h" @@ -58,22 +59,6 @@ static void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page, } /** - * gfs2_get_block - Fills in a buffer head with details about a block - * @inode: The inode - * @lblock: The block number to look up - * @bh_result: The buffer head to return the result in - * @create: Non-zero if we may add block to the file - * - * Returns: errno - */ - -int gfs2_get_block(struct inode *inode, sector_t lblock, - struct buffer_head *bh_result, int create) -{ - return gfs2_block_map(inode, lblock, create, bh_result); -} - -/** * gfs2_get_block_noalloc - Fills in a buffer head with details about a block * @inode: The inode * @lblock: The block number to look up @@ -88,7 +73,7 @@ static int gfs2_get_block_noalloc(struct inode *inode, sector_t lblock, { int error; - error = gfs2_block_map(inode, lblock, 0, bh_result); + error = gfs2_block_map(inode, lblock, bh_result, 0); if (error) return error; if (!buffer_mapped(bh_result)) @@ -99,20 +84,19 @@ static int gfs2_get_block_noalloc(struct inode *inode, sector_t lblock, static int gfs2_get_block_direct(struct inode *inode, sector_t lblock, struct buffer_head *bh_result, int create) { - return gfs2_block_map(inode, lblock, 0, bh_result); + return gfs2_block_map(inode, lblock, bh_result, 0); } /** - * gfs2_writepage - Write complete page - * @page: Page to write + * gfs2_writepage_common - Common bits of writepage + * @page: The page to be written + * @wbc: The writeback control * - * Returns: errno - * - * Some of this is copied from block_write_full_page() although we still - * call it to do most of the work. + * Returns: 1 if writepage is ok, otherwise an error code or zero if no error. */ -static int gfs2_writepage(struct page *page, struct writeback_control *wbc) +static int gfs2_writepage_common(struct page *page, + struct writeback_control *wbc) { struct inode *inode = page->mapping->host; struct gfs2_inode *ip = GFS2_I(inode); @@ -120,41 +104,133 @@ static int gfs2_writepage(struct page *page, struct writeback_control *wbc) loff_t i_size = i_size_read(inode); pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT; unsigned offset; - int error; - int done_trans = 0; + int ret = -EIO; - if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(ip->i_gl))) { - unlock_page(page); - return -EIO; - } + if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(ip->i_gl))) + goto out; + ret = 0; if (current->journal_info) - goto out_ignore; - + goto redirty; /* Is the page fully outside i_size? (truncate in progress) */ - offset = i_size & (PAGE_CACHE_SIZE-1); + offset = i_size & (PAGE_CACHE_SIZE-1); if (page->index > end_index || (page->index == end_index && !offset)) { page->mapping->a_ops->invalidatepage(page, 0); - unlock_page(page); - return 0; /* don't care */ + goto out; + } + return 1; +redirty: + redirty_page_for_writepage(wbc, page); +out: + unlock_page(page); + return 0; +} + +/** + * gfs2_writeback_writepage - Write page for writeback mappings + * @page: The page + * @wbc: The writeback control + * + */ + +static int gfs2_writeback_writepage(struct page *page, + struct writeback_control *wbc) +{ + int ret; + + ret = gfs2_writepage_common(page, wbc); + if (ret <= 0) + return ret; + + ret = mpage_writepage(page, gfs2_get_block_noalloc, wbc); + if (ret == -EAGAIN) + ret = block_write_full_page(page, gfs2_get_block_noalloc, wbc); + return ret; +} + +/** + * gfs2_ordered_writepage - Write page for ordered data files + * @page: The page to write + * @wbc: The writeback control + * + */ + +static int gfs2_ordered_writepage(struct page *page, + struct writeback_control *wbc) +{ + struct inode *inode = page->mapping->host; + struct gfs2_inode *ip = GFS2_I(inode); + int ret; + + ret = gfs2_writepage_common(page, wbc); + if (ret <= 0) + return ret; + + if (!page_has_buffers(page)) { + create_empty_buffers(page, inode->i_sb->s_blocksize, + (1 << BH_Dirty)|(1 << BH_Uptodate)); } + gfs2_page_add_databufs(ip, page, 0, inode->i_sb->s_blocksize-1); + return block_write_full_page(page, gfs2_get_block_noalloc, wbc); +} - if ((sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip)) && - PageChecked(page)) { +/** + * __gfs2_jdata_writepage - The core of jdata writepage + * @page: The page to write + * @wbc: The writeback control + * + * This is shared between writepage and writepages and implements the + * core of the writepage operation. If a transaction is required then + * PageChecked will have been set and the transaction will have + * already been started before this is called. + */ + +static int __gfs2_jdata_writepage(struct page *page, struct writeback_control *wbc) +{ + struct inode *inode = page->mapping->host; + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); + + if (PageChecked(page)) { ClearPageChecked(page); - error = gfs2_trans_begin(sdp, RES_DINODE + 1, 0); - if (error) - goto out_ignore; if (!page_has_buffers(page)) { create_empty_buffers(page, inode->i_sb->s_blocksize, (1 << BH_Dirty)|(1 << BH_Uptodate)); } gfs2_page_add_databufs(ip, page, 0, sdp->sd_vfs->s_blocksize-1); + } + return block_write_full_page(page, gfs2_get_block_noalloc, wbc); +} + +/** + * gfs2_jdata_writepage - Write complete page + * @page: Page to write + * + * Returns: errno + * + */ + +static int gfs2_jdata_writepage(struct page *page, struct writeback_control *wbc) +{ + struct inode *inode = page->mapping->host; + struct gfs2_sbd *sdp = GFS2_SB(inode); + int error; + int done_trans = 0; + + error = gfs2_writepage_common(page, wbc); + if (error <= 0) + return error; + + if (PageChecked(page)) { + if (wbc->sync_mode != WB_SYNC_ALL) + goto out_ignore; + error = gfs2_trans_begin(sdp, RES_DINODE + 1, 0); + if (error) + goto out_ignore; done_trans = 1; } - error = block_write_full_page(page, gfs2_get_block_noalloc, wbc); + error = __gfs2_jdata_writepage(page, wbc); if (done_trans) gfs2_trans_end(sdp); - gfs2_meta_cache_flush(ip); return error; out_ignore: @@ -164,29 +240,190 @@ out_ignore: } /** - * gfs2_writepages - Write a bunch of dirty pages back to disk + * gfs2_writeback_writepages - Write a bunch of dirty pages back to disk * @mapping: The mapping to write * @wbc: Write-back control * - * For journaled files and/or ordered writes this just falls back to the - * kernel's default writepages path for now. We will probably want to change - * that eventually (i.e. when we look at allocate on flush). - * - * For the data=writeback case though we can already ignore buffer heads + * For the data=writeback case we can already ignore buffer heads * and write whole extents at once. This is a big reduction in the * number of I/O requests we send and the bmap calls we make in this case. */ -static int gfs2_writepages(struct address_space *mapping, - struct writeback_control *wbc) +static int gfs2_writeback_writepages(struct address_space *mapping, + struct writeback_control *wbc) +{ + return mpage_writepages(mapping, wbc, gfs2_get_block_noalloc); +} + +/** + * gfs2_write_jdata_pagevec - Write back a pagevec's worth of pages + * @mapping: The mapping + * @wbc: The writeback control + * @writepage: The writepage function to call for each page + * @pvec: The vector of pages + * @nr_pages: The number of pages to write + * + * Returns: non-zero if loop should terminate, zero otherwise + */ + +static int gfs2_write_jdata_pagevec(struct address_space *mapping, + struct writeback_control *wbc, + struct pagevec *pvec, + int nr_pages, pgoff_t end) { struct inode *inode = mapping->host; - struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); + loff_t i_size = i_size_read(inode); + pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT; + unsigned offset = i_size & (PAGE_CACHE_SIZE-1); + unsigned nrblocks = nr_pages * (PAGE_CACHE_SIZE/inode->i_sb->s_blocksize); + struct backing_dev_info *bdi = mapping->backing_dev_info; + int i; + int ret; + + ret = gfs2_trans_begin(sdp, nrblocks, 0); + if (ret < 0) + return ret; + + for(i = 0; i < nr_pages; i++) { + struct page *page = pvec->pages[i]; + + lock_page(page); + + if (unlikely(page->mapping != mapping)) { + unlock_page(page); + continue; + } + + if (!wbc->range_cyclic && page->index > end) { + ret = 1; + unlock_page(page); + continue; + } + + if (wbc->sync_mode != WB_SYNC_NONE) + wait_on_page_writeback(page); + + if (PageWriteback(page) || + !clear_page_dirty_for_io(page)) { + unlock_page(page); + continue; + } + + /* Is the page fully outside i_size? (truncate in progress) */ + if (page->index > end_index || (page->index == end_index && !offset)) { + page->mapping->a_ops->invalidatepage(page, 0); + unlock_page(page); + continue; + } + + ret = __gfs2_jdata_writepage(page, wbc); + + if (ret || (--(wbc->nr_to_write) <= 0)) + ret = 1; + if (wbc->nonblocking && bdi_write_congested(bdi)) { + wbc->encountered_congestion = 1; + ret = 1; + } + + } + gfs2_trans_end(sdp); + return ret; +} + +/** + * gfs2_write_cache_jdata - Like write_cache_pages but different + * @mapping: The mapping to write + * @wbc: The writeback control + * @writepage: The writepage function to call + * @data: The data to pass to writepage + * + * The reason that we use our own function here is that we need to + * start transactions before we grab page locks. This allows us + * to get the ordering right. + */ + +static int gfs2_write_cache_jdata(struct address_space *mapping, + struct writeback_control *wbc) +{ + struct backing_dev_info *bdi = mapping->backing_dev_info; + int ret = 0; + int done = 0; + struct pagevec pvec; + int nr_pages; + pgoff_t index; + pgoff_t end; + int scanned = 0; + int range_whole = 0; + + if (wbc->nonblocking && bdi_write_congested(bdi)) { + wbc->encountered_congestion = 1; + return 0; + } + + pagevec_init(&pvec, 0); + if (wbc->range_cyclic) { + index = mapping->writeback_index; /* Start from prev offset */ + end = -1; + } else { + index = wbc->range_start >> PAGE_CACHE_SHIFT; + end = wbc->range_end >> PAGE_CACHE_SHIFT; + if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) + range_whole = 1; + scanned = 1; + } - if (sdp->sd_args.ar_data == GFS2_DATA_WRITEBACK && !gfs2_is_jdata(ip)) - return mpage_writepages(mapping, wbc, gfs2_get_block_noalloc); +retry: + while (!done && (index <= end) && + (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, + PAGECACHE_TAG_DIRTY, + min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1))) { + scanned = 1; + ret = gfs2_write_jdata_pagevec(mapping, wbc, &pvec, nr_pages, end); + if (ret) + done = 1; + if (ret > 0) + ret = 0; + + pagevec_release(&pvec); + cond_resched(); + } + + if (!scanned && !done) { + /* + * We hit the last page and there is more work to be done: wrap + * back to the start of the file + */ + scanned = 1; + index = 0; + goto retry; + } + + if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) + mapping->writeback_index = index; + return ret; +} + + +/** + * gfs2_jdata_writepages - Write a bunch of dirty pages back to disk + * @mapping: The mapping to write + * @wbc: The writeback control + * + */ - return generic_writepages(mapping, wbc); +static int gfs2_jdata_writepages(struct address_space *mapping, + struct writeback_control *wbc) +{ + struct gfs2_inode *ip = GFS2_I(mapping->host); + struct gfs2_sbd *sdp = GFS2_SB(mapping->host); + int ret; + + ret = gfs2_write_cache_jdata(mapping, wbc); + if (ret == 0 && wbc->sync_mode == WB_SYNC_ALL) { + gfs2_log_flush(sdp, ip->i_gl); + ret = gfs2_write_cache_jdata(mapping, wbc); + } + return ret; } /** @@ -231,62 +468,107 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page) /** - * gfs2_readpage - readpage with locking - * @file: The file to read a page for. N.B. This may be NULL if we are - * reading an internal file. + * __gfs2_readpage - readpage + * @file: The file to read a page for * @page: The page to read * - * Returns: errno + * This is the core of gfs2's readpage. Its used by the internal file + * reading code as in that case we already hold the glock. Also its + * called by gfs2_readpage() once the required lock has been granted. + * */ -static int gfs2_readpage(struct file *file, struct page *page) +static int __gfs2_readpage(void *file, struct page *page) { struct gfs2_inode *ip = GFS2_I(page->mapping->host); struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host); - struct gfs2_file *gf = NULL; - struct gfs2_holder gh; int error; - int do_unlock = 0; - - if (likely(file != &gfs2_internal_file_sentinel)) { - if (file) { - gf = file->private_data; - if (test_bit(GFF_EXLOCK, &gf->f_flags)) - /* gfs2_sharewrite_fault has grabbed the ip->i_gl already */ - goto skip_lock; - } - gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|LM_FLAG_TRY_1CB, &gh); - do_unlock = 1; - error = gfs2_glock_nq_atime(&gh); - if (unlikely(error)) - goto out_unlock; - } -skip_lock: if (gfs2_is_stuffed(ip)) { error = stuffed_readpage(ip, page); unlock_page(page); - } else - error = mpage_readpage(page, gfs2_get_block); + } else { + error = mpage_readpage(page, gfs2_block_map); + } if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) - error = -EIO; + return -EIO; + + return error; +} + +/** + * gfs2_readpage - read a page of a file + * @file: The file to read + * @page: The page of the file + * + * This deals with the locking required. We use a trylock in order to + * avoid the page lock / glock ordering problems returning AOP_TRUNCATED_PAGE + * in the event that we are unable to get the lock. + */ + +static int gfs2_readpage(struct file *file, struct page *page) +{ + struct gfs2_inode *ip = GFS2_I(page->mapping->host); + struct gfs2_holder gh; + int error; - if (do_unlock) { - gfs2_glock_dq_m(1, &gh); - gfs2_holder_uninit(&gh); + gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|LM_FLAG_TRY_1CB, &gh); + error = gfs2_glock_nq_atime(&gh); + if (unlikely(error)) { + unlock_page(page); + goto out; } + error = __gfs2_readpage(file, page); + gfs2_glock_dq(&gh); out: - return error; -out_unlock: - unlock_page(page); + gfs2_holder_uninit(&gh); if (error == GLR_TRYFAILED) { - error = AOP_TRUNCATED_PAGE; yield(); + return AOP_TRUNCATED_PAGE; } - if (do_unlock) - gfs2_holder_uninit(&gh); - goto out; + return error; +} + +/** + * gfs2_internal_read - read an internal file + * @ip: The gfs2 inode + * @ra_state: The readahead state (or NULL for no readahead) + * @buf: The buffer to fill + * @pos: The file position + * @size: The amount to read + * + */ + +int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state, + char *buf, loff_t *pos, unsigned size) +{ + struct address_space *mapping = ip->i_inode.i_mapping; + unsigned long index = *pos / PAGE_CACHE_SIZE; + unsigned offset = *pos & (PAGE_CACHE_SIZE - 1); + unsigned copied = 0; + unsigned amt; + struct page *page; + void *p; + + do { + amt = size - copied; + if (offset + size > PAGE_CACHE_SIZE) + amt = PAGE_CACHE_SIZE - offset; + page = read_cache_page(mapping, index, __gfs2_readpage, NULL); + if (IS_ERR(page)) + return PTR_ERR(page); + p = kmap_atomic(page, KM_USER0); + memcpy(buf + copied, p + offset, amt); + kunmap_atomic(p, KM_USER0); + mark_page_accessed(page); + page_cache_release(page); + copied += amt; + index++; + offset = 0; + } while(copied < size); + (*pos) += size; + return size; } /** @@ -300,10 +582,9 @@ out_unlock: * Any I/O we ignore at this time will be done via readpage later. * 2. We don't handle stuffed files here we let readpage do the honours. * 3. mpage_readpages() does most of the heavy lifting in the common case. - * 4. gfs2_get_block() is relied upon to set BH_Boundary in the right places. - * 5. We use LM_FLAG_TRY_1CB here, effectively we then have lock-ahead as - * well as read-ahead. + * 4. gfs2_block_map() is relied upon to set BH_Boundary in the right places. */ + static int gfs2_readpages(struct file *file, struct address_space *mapping, struct list_head *pages, unsigned nr_pages) { @@ -311,42 +592,20 @@ static int gfs2_readpages(struct file *file, struct address_space *mapping, struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); struct gfs2_holder gh; - int ret = 0; - int do_unlock = 0; + int ret; - if (likely(file != &gfs2_internal_file_sentinel)) { - if (file) { - struct gfs2_file *gf = file->private_data; - if (test_bit(GFF_EXLOCK, &gf->f_flags)) - goto skip_lock; - } - gfs2_holder_init(ip->i_gl, LM_ST_SHARED, - LM_FLAG_TRY_1CB|GL_ATIME, &gh); - do_unlock = 1; - ret = gfs2_glock_nq_atime(&gh); - if (ret == GLR_TRYFAILED) - goto out_noerror; - if (unlikely(ret)) - goto out_unlock; - } -skip_lock: + gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh); + ret = gfs2_glock_nq_atime(&gh); + if (unlikely(ret)) + goto out_uninit; if (!gfs2_is_stuffed(ip)) - ret = mpage_readpages(mapping, pages, nr_pages, gfs2_get_block); - - if (do_unlock) { - gfs2_glock_dq_m(1, &gh); - gfs2_holder_uninit(&gh); - } -out: + ret = mpage_readpages(mapping, pages, nr_pages, gfs2_block_map); + gfs2_glock_dq(&gh); +out_uninit: + gfs2_holder_uninit(&gh); if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) ret = -EIO; return ret; -out_noerror: - ret = 0; -out_unlock: - if (do_unlock) - gfs2_holder_uninit(&gh); - goto out; } /** @@ -382,20 +641,11 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping, if (unlikely(error)) goto out_uninit; - error = -ENOMEM; - page = __grab_cache_page(mapping, index); - *pagep = page; - if (!page) - goto out_unlock; - gfs2_write_calc_reserv(ip, len, &data_blocks, &ind_blocks); - error = gfs2_write_alloc_required(ip, pos, len, &alloc_required); if (error) - goto out_putpage; - + goto out_unlock; - ip->i_alloc.al_requested = 0; if (alloc_required) { al = gfs2_alloc_get(ip); @@ -424,40 +674,47 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping, if (error) goto out_trans_fail; + error = -ENOMEM; + page = __grab_cache_page(mapping, index); + *pagep = page; + if (unlikely(!page)) + goto out_endtrans; + if (gfs2_is_stuffed(ip)) { + error = 0; if (pos + len > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) { error = gfs2_unstuff_dinode(ip, page); if (error == 0) goto prepare_write; - } else if (!PageUptodate(page)) + } else if (!PageUptodate(page)) { error = stuffed_readpage(ip, page); + } goto out; } prepare_write: - error = block_prepare_write(page, from, to, gfs2_get_block); - + error = block_prepare_write(page, from, to, gfs2_block_map); out: - if (error) { - gfs2_trans_end(sdp); + if (error == 0) + return 0; + + page_cache_release(page); + if (pos + len > ip->i_inode.i_size) + vmtruncate(&ip->i_inode, ip->i_inode.i_size); +out_endtrans: + gfs2_trans_end(sdp); out_trans_fail: - if (alloc_required) { - gfs2_inplace_release(ip); + if (alloc_required) { + gfs2_inplace_release(ip); out_qunlock: - gfs2_quota_unlock(ip); + gfs2_quota_unlock(ip); out_alloc_put: - gfs2_alloc_put(ip); - } -out_putpage: - page_cache_release(page); - if (pos + len > ip->i_inode.i_size) - vmtruncate(&ip->i_inode, ip->i_inode.i_size); + gfs2_alloc_put(ip); + } out_unlock: - gfs2_glock_dq_m(1, &ip->i_gh); + gfs2_glock_dq(&ip->i_gh); out_uninit: - gfs2_holder_uninit(&ip->i_gh); - } - + gfs2_holder_uninit(&ip->i_gh); return error; } @@ -565,7 +822,7 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping, struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); struct buffer_head *dibh; - struct gfs2_alloc *al = &ip->i_alloc; + struct gfs2_alloc *al = ip->i_alloc; struct gfs2_dinode *di; unsigned int from = pos & (PAGE_CACHE_SIZE - 1); unsigned int to = from + len; @@ -585,19 +842,16 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping, if (gfs2_is_stuffed(ip)) return gfs2_stuffed_write_end(inode, dibh, pos, len, copied, page); - if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip)) + if (!gfs2_is_writeback(ip)) gfs2_page_add_databufs(ip, page, from, to); ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata); - if (likely(ret >= 0)) { - copied = ret; - if ((pos + copied) > inode->i_size) { - di = (struct gfs2_dinode *)dibh->b_data; - ip->i_di.di_size = inode->i_size; - di->di_size = cpu_to_be64(inode->i_size); - mark_inode_dirty(inode); - } + if (likely(ret >= 0) && (inode->i_size > ip->i_di.di_size)) { + di = (struct gfs2_dinode *)dibh->b_data; + ip->i_di.di_size = inode->i_size; + di->di_size = cpu_to_be64(inode->i_size); + mark_inode_dirty(inode); } if (inode == sdp->sd_rindex) @@ -606,7 +860,7 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping, brelse(dibh); gfs2_trans_end(sdp); failed: - if (al->al_requested) { + if (al) { gfs2_inplace_release(ip); gfs2_quota_unlock(ip); gfs2_alloc_put(ip); @@ -625,11 +879,7 @@ failed: static int gfs2_set_page_dirty(struct page *page) { - struct gfs2_inode *ip = GFS2_I(page->mapping->host); - struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host); - - if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip)) - SetPageChecked(page); + SetPageChecked(page); return __set_page_dirty_buffers(page); } @@ -653,7 +903,7 @@ static sector_t gfs2_bmap(struct address_space *mapping, sector_t lblock) return 0; if (!gfs2_is_stuffed(ip)) - dblock = generic_block_bmap(mapping, lblock, gfs2_get_block); + dblock = generic_block_bmap(mapping, lblock, gfs2_block_map); gfs2_glock_dq_uninit(&i_gh); @@ -719,13 +969,9 @@ static int gfs2_ok_for_dio(struct gfs2_inode *ip, int rw, loff_t offset) { /* * Should we return an error here? I can't see that O_DIRECT for - * a journaled file makes any sense. For now we'll silently fall - * back to buffered I/O, likewise we do the same for stuffed - * files since they are (a) small and (b) unaligned. + * a stuffed file makes any sense. For now we'll silently fall + * back to buffered I/O */ - if (gfs2_is_jdata(ip)) - return 0; - if (gfs2_is_stuffed(ip)) return 0; @@ -836,9 +1082,23 @@ cannot_release: return 0; } -const struct address_space_operations gfs2_file_aops = { - .writepage = gfs2_writepage, - .writepages = gfs2_writepages, +static const struct address_space_operations gfs2_writeback_aops = { + .writepage = gfs2_writeback_writepage, + .writepages = gfs2_writeback_writepages, + .readpage = gfs2_readpage, + .readpages = gfs2_readpages, + .sync_page = block_sync_page, + .write_begin = gfs2_write_begin, + .write_end = gfs2_write_end, + .bmap = gfs2_bmap, + .invalidatepage = gfs2_invalidatepage, + .releasepage = gfs2_releasepage, + .direct_IO = gfs2_direct_IO, + .migratepage = buffer_migrate_page, +}; + +static const struct address_space_operations gfs2_ordered_aops = { + .writepage = gfs2_ordered_writepage, .readpage = gfs2_readpage, .readpages = gfs2_readpages, .sync_page = block_sync_page, @@ -849,5 +1109,34 @@ const struct address_space_operations gfs2_file_aops = { .invalidatepage = gfs2_invalidatepage, .releasepage = gfs2_releasepage, .direct_IO = gfs2_direct_IO, + .migratepage = buffer_migrate_page, }; +static const struct address_space_operations gfs2_jdata_aops = { + .writepage = gfs2_jdata_writepage, + .writepages = gfs2_jdata_writepages, + .readpage = gfs2_readpage, + .readpages = gfs2_readpages, + .sync_page = block_sync_page, + .write_begin = gfs2_write_begin, + .write_end = gfs2_write_end, + .set_page_dirty = gfs2_set_page_dirty, + .bmap = gfs2_bmap, + .invalidatepage = gfs2_invalidatepage, + .releasepage = gfs2_releasepage, +}; + +void gfs2_set_aops(struct inode *inode) +{ + struct gfs2_inode *ip = GFS2_I(inode); + + if (gfs2_is_writeback(ip)) + inode->i_mapping->a_ops = &gfs2_writeback_aops; + else if (gfs2_is_ordered(ip)) + inode->i_mapping->a_ops = &gfs2_ordered_aops; + else if (gfs2_is_jdata(ip)) + inode->i_mapping->a_ops = &gfs2_jdata_aops; + else + BUG(); +} + diff --git a/fs/gfs2/ops_address.h b/fs/gfs2/ops_address.h index fa1b5b3d28b9..5da21285bba4 100644 --- a/fs/gfs2/ops_address.h +++ b/fs/gfs2/ops_address.h @@ -14,9 +14,10 @@ #include <linux/buffer_head.h> #include <linux/mm.h> -extern const struct address_space_operations gfs2_file_aops; -extern int gfs2_get_block(struct inode *inode, sector_t lblock, - struct buffer_head *bh_result, int create); extern int gfs2_releasepage(struct page *page, gfp_t gfp_mask); +extern int gfs2_internal_read(struct gfs2_inode *ip, + struct file_ra_state *ra_state, + char *buf, loff_t *pos, unsigned size); +extern void gfs2_set_aops(struct inode *inode); #endif /* __OPS_ADDRESS_DOT_H__ */ diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index bb11fd6752d3..f4842f2548cd 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -33,57 +33,12 @@ #include "lm.h" #include "log.h" #include "meta_io.h" -#include "ops_file.h" -#include "ops_vm.h" #include "quota.h" #include "rgrp.h" #include "trans.h" #include "util.h" #include "eaops.h" - -/* - * Most fields left uninitialised to catch anybody who tries to - * use them. f_flags set to prevent file_accessed() from touching - * any other part of this. Its use is purely as a flag so that we - * know (in readpage()) whether or not do to locking. - */ -struct file gfs2_internal_file_sentinel = { - .f_flags = O_NOATIME|O_RDONLY, -}; - -static int gfs2_read_actor(read_descriptor_t *desc, struct page *page, - unsigned long offset, unsigned long size) -{ - char *kaddr; - unsigned long count = desc->count; - - if (size > count) - size = count; - - kaddr = kmap(page); - memcpy(desc->arg.data, kaddr + offset, size); - kunmap(page); - - desc->count = count - size; - desc->written += size; - desc->arg.buf += size; - return size; -} - -int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state, - char *buf, loff_t *pos, unsigned size) -{ - struct inode *inode = &ip->i_inode; - read_descriptor_t desc; - desc.written = 0; - desc.arg.data = buf; - desc.count = size; - desc.error = 0; - do_generic_mapping_read(inode->i_mapping, ra_state, - &gfs2_internal_file_sentinel, pos, &desc, - gfs2_read_actor); - return desc.written ? desc.written : desc.error; -} +#include "ops_address.h" /** * gfs2_llseek - seek to a location in a file @@ -214,7 +169,7 @@ static int gfs2_get_flags(struct file *filp, u32 __user *ptr) if (put_user(fsflags, ptr)) error = -EFAULT; - gfs2_glock_dq_m(1, &gh); + gfs2_glock_dq(&gh); gfs2_holder_uninit(&gh); return error; } @@ -291,7 +246,16 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) if (error) goto out; } - + if ((flags ^ new_flags) & GFS2_DIF_JDATA) { + if (flags & GFS2_DIF_JDATA) + gfs2_log_flush(sdp, ip->i_gl); + error = filemap_fdatawrite(inode->i_mapping); + if (error) + goto out; + error = filemap_fdatawait(inode->i_mapping); + if (error) + goto out; + } error = gfs2_trans_begin(sdp, RES_DINODE, 0); if (error) goto out; @@ -303,6 +267,7 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) gfs2_dinode_out(ip, bh->b_data); brelse(bh); gfs2_set_inode_flags(inode); + gfs2_set_aops(inode); out_trans_end: gfs2_trans_end(sdp); out: @@ -338,6 +303,128 @@ static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return -ENOTTY; } +/** + * gfs2_allocate_page_backing - Use bmap to allocate blocks + * @page: The (locked) page to allocate backing for + * + * We try to allocate all the blocks required for the page in + * one go. This might fail for various reasons, so we keep + * trying until all the blocks to back this page are allocated. + * If some of the blocks are already allocated, thats ok too. + */ + +static int gfs2_allocate_page_backing(struct page *page) +{ + struct inode *inode = page->mapping->host; + struct buffer_head bh; + unsigned long size = PAGE_CACHE_SIZE; + u64 lblock = page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits); + + do { + bh.b_state = 0; + bh.b_size = size; + gfs2_block_map(inode, lblock, &bh, 1); + if (!buffer_mapped(&bh)) + return -EIO; + size -= bh.b_size; + lblock += (bh.b_size >> inode->i_blkbits); + } while(size > 0); + return 0; +} + +/** + * gfs2_page_mkwrite - Make a shared, mmap()ed, page writable + * @vma: The virtual memory area + * @page: The page which is about to become writable + * + * When the page becomes writable, we need to ensure that we have + * blocks allocated on disk to back that page. + */ + +static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct page *page) +{ + struct inode *inode = vma->vm_file->f_path.dentry->d_inode; + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); + unsigned long last_index; + u64 pos = page->index << (PAGE_CACHE_SIZE - inode->i_blkbits); + unsigned int data_blocks, ind_blocks, rblocks; + int alloc_required = 0; + struct gfs2_holder gh; + struct gfs2_alloc *al; + int ret; + + gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_ATIME, &gh); + ret = gfs2_glock_nq_atime(&gh); + if (ret) + goto out; + + set_bit(GIF_SW_PAGED, &ip->i_flags); + gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, &data_blocks, &ind_blocks); + ret = gfs2_write_alloc_required(ip, pos, PAGE_CACHE_SIZE, &alloc_required); + if (ret || !alloc_required) + goto out_unlock; + ret = -ENOMEM; + al = gfs2_alloc_get(ip); + if (al == NULL) + goto out_unlock; + + ret = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (ret) + goto out_alloc_put; + ret = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid); + if (ret) + goto out_quota_unlock; + al->al_requested = data_blocks + ind_blocks; + ret = gfs2_inplace_reserve(ip); + if (ret) + goto out_quota_unlock; + + rblocks = RES_DINODE + ind_blocks; + if (gfs2_is_jdata(ip)) + rblocks += data_blocks ? data_blocks : 1; + if (ind_blocks || data_blocks) + rblocks += RES_STATFS + RES_QUOTA; + ret = gfs2_trans_begin(sdp, rblocks, 0); + if (ret) + goto out_trans_fail; + + lock_page(page); + ret = -EINVAL; + last_index = ip->i_inode.i_size >> PAGE_CACHE_SHIFT; + if (page->index > last_index) + goto out_unlock_page; + ret = 0; + if (!PageUptodate(page) || page->mapping != ip->i_inode.i_mapping) + goto out_unlock_page; + if (gfs2_is_stuffed(ip)) { + ret = gfs2_unstuff_dinode(ip, page); + if (ret) + goto out_unlock_page; + } + ret = gfs2_allocate_page_backing(page); + +out_unlock_page: + unlock_page(page); + gfs2_trans_end(sdp); +out_trans_fail: + gfs2_inplace_release(ip); +out_quota_unlock: + gfs2_quota_unlock(ip); +out_alloc_put: + gfs2_alloc_put(ip); +out_unlock: + gfs2_glock_dq(&gh); +out: + gfs2_holder_uninit(&gh); + return ret; +} + +static struct vm_operations_struct gfs2_vm_ops = { + .fault = filemap_fault, + .page_mkwrite = gfs2_page_mkwrite, +}; + /** * gfs2_mmap - @@ -360,14 +447,7 @@ static int gfs2_mmap(struct file *file, struct vm_area_struct *vma) return error; } - /* This is VM_MAYWRITE instead of VM_WRITE because a call - to mprotect() can turn on VM_WRITE later. */ - - if ((vma->vm_flags & (VM_MAYSHARE | VM_MAYWRITE)) == - (VM_MAYSHARE | VM_MAYWRITE)) - vma->vm_ops = &gfs2_vm_ops_sharewrite; - else - vma->vm_ops = &gfs2_vm_ops_private; + vma->vm_ops = &gfs2_vm_ops; gfs2_glock_dq_uninit(&i_gh); @@ -538,15 +618,6 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl) if (__mandatory_lock(&ip->i_inode)) return -ENOLCK; - if (sdp->sd_args.ar_localflocks) { - if (IS_GETLK(cmd)) { - posix_test_lock(file, fl); - return 0; - } else { - return posix_lock_file_wait(file, fl); - } - } - if (cmd == F_CANCELLK) { /* Hack: */ cmd = F_SETLK; @@ -632,16 +703,12 @@ static void do_unflock(struct file *file, struct file_lock *fl) static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl) { struct gfs2_inode *ip = GFS2_I(file->f_mapping->host); - struct gfs2_sbd *sdp = GFS2_SB(file->f_mapping->host); if (!(fl->fl_flags & FL_FLOCK)) return -ENOLCK; if (__mandatory_lock(&ip->i_inode)) return -ENOLCK; - if (sdp->sd_args.ar_localflocks) - return flock_lock_file_wait(file, fl); - if (fl->fl_type == F_UNLCK) { do_unflock(file, fl); return 0; @@ -678,3 +745,27 @@ const struct file_operations gfs2_dir_fops = { .flock = gfs2_flock, }; +const struct file_operations gfs2_file_fops_nolock = { + .llseek = gfs2_llseek, + .read = do_sync_read, + .aio_read = generic_file_aio_read, + .write = do_sync_write, + .aio_write = generic_file_aio_write, + .unlocked_ioctl = gfs2_ioctl, + .mmap = gfs2_mmap, + .open = gfs2_open, + .release = gfs2_close, + .fsync = gfs2_fsync, + .splice_read = generic_file_splice_read, + .splice_write = generic_file_splice_write, + .setlease = gfs2_setlease, +}; + +const struct file_operations gfs2_dir_fops_nolock = { + .readdir = gfs2_readdir, + .unlocked_ioctl = gfs2_ioctl, + .open = gfs2_open, + .release = gfs2_close, + .fsync = gfs2_fsync, +}; + diff --git a/fs/gfs2/ops_file.h b/fs/gfs2/ops_file.h deleted file mode 100644 index 7e5d8ec9c846..000000000000 --- a/fs/gfs2/ops_file.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. - * - * This copyrighted material is made available to anyone wishing to use, - * modify, copy, or redistribute it subject to the terms and conditions - * of the GNU General Public License version 2. - */ - -#ifndef __OPS_FILE_DOT_H__ -#define __OPS_FILE_DOT_H__ - -#include <linux/fs.h> -struct gfs2_inode; - -extern struct file gfs2_internal_file_sentinel; -extern int gfs2_internal_read(struct gfs2_inode *ip, - struct file_ra_state *ra_state, - char *buf, loff_t *pos, unsigned size); -extern void gfs2_set_inode_flags(struct inode *inode); -extern const struct file_operations gfs2_file_fops; -extern const struct file_operations gfs2_dir_fops; - -#endif /* __OPS_FILE_DOT_H__ */ diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 17de58e83d92..43d511bba52d 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -1,6 +1,6 @@ /* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions @@ -21,6 +21,7 @@ #include "gfs2.h" #include "incore.h" +#include "bmap.h" #include "daemon.h" #include "glock.h" #include "glops.h" @@ -59,7 +60,6 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) mutex_init(&sdp->sd_inum_mutex); spin_lock_init(&sdp->sd_statfs_spin); - mutex_init(&sdp->sd_statfs_mutex); spin_lock_init(&sdp->sd_rindex_spin); mutex_init(&sdp->sd_rindex_mutex); @@ -77,7 +77,6 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) spin_lock_init(&sdp->sd_log_lock); - INIT_LIST_HEAD(&sdp->sd_log_le_gl); INIT_LIST_HEAD(&sdp->sd_log_le_buf); INIT_LIST_HEAD(&sdp->sd_log_le_revoke); INIT_LIST_HEAD(&sdp->sd_log_le_rg); @@ -303,6 +302,67 @@ out: return error; } +/** + * map_journal_extents - create a reusable "extent" mapping from all logical + * blocks to all physical blocks for the given journal. This will save + * us time when writing journal blocks. Most journals will have only one + * extent that maps all their logical blocks. That's because gfs2.mkfs + * arranges the journal blocks sequentially to maximize performance. + * So the extent would map the first block for the entire file length. + * However, gfs2_jadd can happen while file activity is happening, so + * those journals may not be sequential. Less likely is the case where + * the users created their own journals by mounting the metafs and + * laying it out. But it's still possible. These journals might have + * several extents. + * + * TODO: This should be done in bigger chunks rather than one block at a time, + * but since it's only done at mount time, I'm not worried about the + * time it takes. + */ +static int map_journal_extents(struct gfs2_sbd *sdp) +{ + struct gfs2_jdesc *jd = sdp->sd_jdesc; + unsigned int lb; + u64 db, prev_db; /* logical block, disk block, prev disk block */ + struct gfs2_inode *ip = GFS2_I(jd->jd_inode); + struct gfs2_journal_extent *jext = NULL; + struct buffer_head bh; + int rc = 0; + + prev_db = 0; + + for (lb = 0; lb < ip->i_di.di_size >> sdp->sd_sb.sb_bsize_shift; lb++) { + bh.b_state = 0; + bh.b_blocknr = 0; + bh.b_size = 1 << ip->i_inode.i_blkbits; + rc = gfs2_block_map(jd->jd_inode, lb, &bh, 0); + db = bh.b_blocknr; + if (rc || !db) { + printk(KERN_INFO "GFS2 journal mapping error %d: lb=" + "%u db=%llu\n", rc, lb, (unsigned long long)db); + break; + } + if (!prev_db || db != prev_db + 1) { + jext = kzalloc(sizeof(struct gfs2_journal_extent), + GFP_KERNEL); + if (!jext) { + printk(KERN_INFO "GFS2 error: out of memory " + "mapping journal extents.\n"); + rc = -ENOMEM; + break; + } + jext->dblock = db; + jext->lblock = lb; + jext->blocks = 1; + list_add_tail(&jext->extent_list, &jd->extent_list); + } else { + jext->blocks++; + } + prev_db = db; + } + return rc; +} + static int init_journal(struct gfs2_sbd *sdp, int undo) { struct gfs2_holder ji_gh; @@ -340,7 +400,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) if (sdp->sd_args.ar_spectator) { sdp->sd_jdesc = gfs2_jdesc_find(sdp, 0); - sdp->sd_log_blks_free = sdp->sd_jdesc->jd_blocks; + atomic_set(&sdp->sd_log_blks_free, sdp->sd_jdesc->jd_blocks); } else { if (sdp->sd_lockstruct.ls_jid >= gfs2_jindex_size(sdp)) { fs_err(sdp, "can't mount journal #%u\n", @@ -377,7 +437,10 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) sdp->sd_jdesc->jd_jid, error); goto fail_jinode_gh; } - sdp->sd_log_blks_free = sdp->sd_jdesc->jd_blocks; + atomic_set(&sdp->sd_log_blks_free, sdp->sd_jdesc->jd_blocks); + + /* Map the extents for this journal's blocks */ + map_journal_extents(sdp); } if (sdp->sd_lockstruct.ls_first) { diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 291f0c7eaa3b..9f71372c1757 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -61,7 +61,7 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry, inode = gfs2_createi(ghs, &dentry->d_name, S_IFREG | mode, 0); if (!IS_ERR(inode)) { gfs2_trans_end(sdp); - if (dip->i_alloc.al_rgd) + if (dip->i_alloc->al_rgd) gfs2_inplace_release(dip); gfs2_quota_unlock(dip); gfs2_alloc_put(dip); @@ -113,8 +113,18 @@ static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry, if (inode && IS_ERR(inode)) return ERR_PTR(PTR_ERR(inode)); - if (inode) + if (inode) { + struct gfs2_glock *gl = GFS2_I(inode)->i_gl; + struct gfs2_holder gh; + int error; + error = gfs2_glock_nq_init(gl, LM_ST_SHARED, LM_FLAG_ANY, &gh); + if (error) { + iput(inode); + return ERR_PTR(error); + } + gfs2_glock_dq_uninit(&gh); return d_splice_alias(inode, dentry); + } d_add(dentry, inode); return NULL; @@ -366,7 +376,7 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry, } gfs2_trans_end(sdp); - if (dip->i_alloc.al_rgd) + if (dip->i_alloc->al_rgd) gfs2_inplace_release(dip); gfs2_quota_unlock(dip); gfs2_alloc_put(dip); @@ -442,7 +452,7 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) gfs2_assert_withdraw(sdp, !error); /* dip already pinned */ gfs2_trans_end(sdp); - if (dip->i_alloc.al_rgd) + if (dip->i_alloc->al_rgd) gfs2_inplace_release(dip); gfs2_quota_unlock(dip); gfs2_alloc_put(dip); @@ -548,7 +558,7 @@ static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode, } gfs2_trans_end(sdp); - if (dip->i_alloc.al_rgd) + if (dip->i_alloc->al_rgd) gfs2_inplace_release(dip); gfs2_quota_unlock(dip); gfs2_alloc_put(dip); diff --git a/fs/gfs2/ops_inode.h b/fs/gfs2/ops_inode.h index 34f0caac1a03..fd8cee231e1d 100644 --- a/fs/gfs2/ops_inode.h +++ b/fs/gfs2/ops_inode.h @@ -16,5 +16,11 @@ extern const struct inode_operations gfs2_file_iops; extern const struct inode_operations gfs2_dir_iops; extern const struct inode_operations gfs2_symlink_iops; extern const struct inode_operations gfs2_dev_iops; +extern const struct file_operations gfs2_file_fops; +extern const struct file_operations gfs2_dir_fops; +extern const struct file_operations gfs2_file_fops_nolock; +extern const struct file_operations gfs2_dir_fops_nolock; + +extern void gfs2_set_inode_flags(struct inode *inode); #endif /* __OPS_INODE_DOT_H__ */ diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 950f31460e8b..5e524217944a 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -487,7 +487,6 @@ static struct inode *gfs2_alloc_inode(struct super_block *sb) if (ip) { ip->i_flags = 0; ip->i_gl = NULL; - ip->i_last_pfault = jiffies; } return &ip->i_inode; } diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c deleted file mode 100644 index 927d739d4685..000000000000 --- a/fs/gfs2/ops_vm.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. - * - * This copyrighted material is made available to anyone wishing to use, - * modify, copy, or redistribute it subject to the terms and conditions - * of the GNU General Public License version 2. - */ - -#include <linux/slab.h> -#include <linux/spinlock.h> -#include <linux/completion.h> -#include <linux/buffer_head.h> -#include <linux/mm.h> -#include <linux/pagemap.h> -#include <linux/gfs2_ondisk.h> -#include <linux/lm_interface.h> - -#include "gfs2.h" -#include "incore.h" -#include "bmap.h" -#include "glock.h" -#include "inode.h" -#include "ops_vm.h" -#include "quota.h" -#include "rgrp.h" -#include "trans.h" -#include "util.h" - -static int gfs2_private_fault(struct vm_area_struct *vma, struct vm_fault *vmf) -{ - struct gfs2_inode *ip = GFS2_I(vma->vm_file->f_mapping->host); - - set_bit(GIF_PAGED, &ip->i_flags); - return filemap_fault(vma, vmf); -} - -static int alloc_page_backing(struct gfs2_inode *ip, struct page *page) -{ - struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); - unsigned long index = page->index; - u64 lblock = index << (PAGE_CACHE_SHIFT - - sdp->sd_sb.sb_bsize_shift); - unsigned int blocks = PAGE_CACHE_SIZE >> sdp->sd_sb.sb_bsize_shift; - struct gfs2_alloc *al; - unsigned int data_blocks, ind_blocks; - unsigned int x; - int error; - - al = gfs2_alloc_get(ip); - - error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); - if (error) - goto out; - - error = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid); - if (error) - goto out_gunlock_q; - - gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, &data_blocks, &ind_blocks); - - al->al_requested = data_blocks + ind_blocks; - - error = gfs2_inplace_reserve(ip); - if (error) - goto out_gunlock_q; - - error = gfs2_trans_begin(sdp, al->al_rgd->rd_length + - ind_blocks + RES_DINODE + - RES_STATFS + RES_QUOTA, 0); - if (error) - goto out_ipres; - - if (gfs2_is_stuffed(ip)) { - error = gfs2_unstuff_dinode(ip, NULL); - if (error) - goto out_trans; - } - - for (x = 0; x < blocks; ) { - u64 dblock; - unsigned int extlen; - int new = 1; - - error = gfs2_extent_map(&ip->i_inode, lblock, &new, &dblock, &extlen); - if (error) - goto out_trans; - - lblock += extlen; - x += extlen; - } - - gfs2_assert_warn(sdp, al->al_alloced); - -out_trans: - gfs2_trans_end(sdp); -out_ipres: - gfs2_inplace_release(ip); -out_gunlock_q: - gfs2_quota_unlock(ip); -out: - gfs2_alloc_put(ip); - return error; -} - -static int gfs2_sharewrite_fault(struct vm_area_struct *vma, - struct vm_fault *vmf) -{ - struct file *file = vma->vm_file; - struct gfs2_file *gf = file->private_data; - struct gfs2_inode *ip = GFS2_I(file->f_mapping->host); - struct gfs2_holder i_gh; - int alloc_required; - int error; - int ret = 0; - - error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); - if (error) - goto out; - - set_bit(GIF_PAGED, &ip->i_flags); - set_bit(GIF_SW_PAGED, &ip->i_flags); - - error = gfs2_write_alloc_required(ip, - (u64)vmf->pgoff << PAGE_CACHE_SHIFT, - PAGE_CACHE_SIZE, &alloc_required); - if (error) { - ret = VM_FAULT_OOM; /* XXX: are these right? */ - goto out_unlock; - } - - set_bit(GFF_EXLOCK, &gf->f_flags); - ret = filemap_fault(vma, vmf); - clear_bit(GFF_EXLOCK, &gf->f_flags); - if (ret & VM_FAULT_ERROR) - goto out_unlock; - - if (alloc_required) { - /* XXX: do we need to drop page lock around alloc_page_backing?*/ - error = alloc_page_backing(ip, vmf->page); - if (error) { - /* - * VM_FAULT_LOCKED should always be the case for - * filemap_fault, but it may not be in a future - * implementation. - */ - if (ret & VM_FAULT_LOCKED) - unlock_page(vmf->page); - page_cache_release(vmf->page); - ret = VM_FAULT_OOM; - goto out_unlock; - } - set_page_dirty(vmf->page); - } - -out_unlock: - gfs2_glock_dq_uninit(&i_gh); -out: - return ret; -} - -struct vm_operations_struct gfs2_vm_ops_private = { - .fault = gfs2_private_fault, -}; - -struct vm_operations_struct gfs2_vm_ops_sharewrite = { - .fault = gfs2_sharewrite_fault, -}; - diff --git a/fs/gfs2/ops_vm.h b/fs/gfs2/ops_vm.h deleted file mode 100644 index 4ae8f43ed5e3..000000000000 --- a/fs/gfs2/ops_vm.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. - * - * This copyrighted material is made available to anyone wishing to use, - * modify, copy, or redistribute it subject to the terms and conditions - * of the GNU General Public License version 2. - */ - -#ifndef __OPS_VM_DOT_H__ -#define __OPS_VM_DOT_H__ - -#include <linux/mm.h> - -extern struct vm_operations_struct gfs2_vm_ops_private; -extern struct vm_operations_struct gfs2_vm_ops_sharewrite; - -#endif /* __OPS_VM_DOT_H__ */ diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index addb51e0f135..a08dabd6ce90 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -1,6 +1,6 @@ /* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions @@ -59,7 +59,6 @@ #include "super.h" #include "trans.h" #include "inode.h" -#include "ops_file.h" #include "ops_address.h" #include "util.h" @@ -274,10 +273,10 @@ static int bh_get(struct gfs2_quota_data *qd) } block = qd->qd_slot / sdp->sd_qc_per_block; - offset = qd->qd_slot % sdp->sd_qc_per_block;; + offset = qd->qd_slot % sdp->sd_qc_per_block; bh_map.b_size = 1 << ip->i_inode.i_blkbits; - error = gfs2_block_map(&ip->i_inode, block, 0, &bh_map); + error = gfs2_block_map(&ip->i_inode, block, &bh_map, 0); if (error) goto fail; error = gfs2_meta_read(ip->i_gl, bh_map.b_blocknr, DIO_WAIT, &bh); @@ -454,7 +453,7 @@ static void qdsb_put(struct gfs2_quota_data *qd) int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); - struct gfs2_alloc *al = &ip->i_alloc; + struct gfs2_alloc *al = ip->i_alloc; struct gfs2_quota_data **qd = al->al_qd; int error; @@ -502,7 +501,7 @@ out: void gfs2_quota_unhold(struct gfs2_inode *ip) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); - struct gfs2_alloc *al = &ip->i_alloc; + struct gfs2_alloc *al = ip->i_alloc; unsigned int x; gfs2_assert_warn(sdp, !test_bit(GIF_QD_LOCKED, &ip->i_flags)); @@ -646,7 +645,7 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, } if (!buffer_mapped(bh)) { - gfs2_get_block(inode, iblock, bh, 1); + gfs2_block_map(inode, iblock, bh, 1); if (!buffer_mapped(bh)) goto unlock; } @@ -793,11 +792,9 @@ static int do_glock(struct gfs2_quota_data *qd, int force_refresh, struct gfs2_holder i_gh; struct gfs2_quota_host q; char buf[sizeof(struct gfs2_quota)]; - struct file_ra_state ra_state; int error; struct gfs2_quota_lvb *qlvb; - file_ra_state_init(&ra_state, sdp->sd_quota_inode->i_mapping); restart: error = gfs2_glock_nq_init(qd->qd_gl, LM_ST_SHARED, 0, q_gh); if (error) @@ -820,8 +817,8 @@ restart: memset(buf, 0, sizeof(struct gfs2_quota)); pos = qd2offset(qd); - error = gfs2_internal_read(ip, &ra_state, buf, - &pos, sizeof(struct gfs2_quota)); + error = gfs2_internal_read(ip, NULL, buf, &pos, + sizeof(struct gfs2_quota)); if (error < 0) goto fail_gunlock; @@ -856,7 +853,7 @@ fail: int gfs2_quota_lock(struct gfs2_inode *ip, u32 uid, u32 gid) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); - struct gfs2_alloc *al = &ip->i_alloc; + struct gfs2_alloc *al = ip->i_alloc; unsigned int x; int error = 0; @@ -924,7 +921,7 @@ static int need_sync(struct gfs2_quota_data *qd) void gfs2_quota_unlock(struct gfs2_inode *ip) { - struct gfs2_alloc *al = &ip->i_alloc; + struct gfs2_alloc *al = ip->i_alloc; struct gfs2_quota_data *qda[4]; unsigned int count = 0; unsigned int x; @@ -972,7 +969,7 @@ static int print_message(struct gfs2_quota_data *qd, char *type) int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); - struct gfs2_alloc *al = &ip->i_alloc; + struct gfs2_alloc *al = ip->i_alloc; struct gfs2_quota_data *qd; s64 value; unsigned int x; @@ -1016,10 +1013,9 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid) void gfs2_quota_change(struct gfs2_inode *ip, s64 change, u32 uid, u32 gid) { - struct gfs2_alloc *al = &ip->i_alloc; + struct gfs2_alloc *al = ip->i_alloc; struct gfs2_quota_data *qd; unsigned int x; - unsigned int found = 0; if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), change)) return; @@ -1032,7 +1028,6 @@ void gfs2_quota_change(struct gfs2_inode *ip, s64 change, if ((qd->qd_id == uid && test_bit(QDF_USER, &qd->qd_flags)) || (qd->qd_id == gid && !test_bit(QDF_USER, &qd->qd_flags))) { do_qc(qd, change); - found++; } } } diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index beb6c7ac0086..b249e294a95b 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -391,7 +391,7 @@ static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header_host *hea lblock = head->lh_blkno; gfs2_replay_incr_blk(sdp, &lblock); bh_map.b_size = 1 << ip->i_inode.i_blkbits; - error = gfs2_block_map(&ip->i_inode, lblock, 0, &bh_map); + error = gfs2_block_map(&ip->i_inode, lblock, &bh_map, 0); if (error) return error; if (!bh_map.b_blocknr) { @@ -504,13 +504,21 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd) if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) ro = 1; } else { - if (sdp->sd_vfs->s_flags & MS_RDONLY) - ro = 1; + if (sdp->sd_vfs->s_flags & MS_RDONLY) { + /* check if device itself is read-only */ + ro = bdev_read_only(sdp->sd_vfs->s_bdev); + if (!ro) { + fs_info(sdp, "recovery required on " + "read-only filesystem.\n"); + fs_info(sdp, "write access will be " + "enabled during recovery.\n"); + } + } } if (ro) { - fs_warn(sdp, "jid=%u: Can't replay: read-only FS\n", - jd->jd_jid); + fs_warn(sdp, "jid=%u: Can't replay: read-only block " + "device\n", jd->jd_jid); error = -EROFS; goto fail_gunlock_tr; } diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 708c287e1d0e..3552110b2e5f 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -25,10 +25,10 @@ #include "rgrp.h" #include "super.h" #include "trans.h" -#include "ops_file.h" #include "util.h" #include "log.h" #include "inode.h" +#include "ops_address.h" #define BFITNOENT ((u32)~0) #define NO_BLOCK ((u64)~0) @@ -126,41 +126,43 @@ static unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, unsigned char *buffer, * Return: the block number (bitmap buffer scope) that was found */ -static u32 gfs2_bitfit(struct gfs2_rgrpd *rgd, unsigned char *buffer, - unsigned int buflen, u32 goal, - unsigned char old_state) +static u32 gfs2_bitfit(unsigned char *buffer, unsigned int buflen, u32 goal, + unsigned char old_state) { - unsigned char *byte, *end, alloc; + unsigned char *byte; u32 blk = goal; - unsigned int bit; + unsigned int bit, bitlong; + unsigned long *plong, plong55; byte = buffer + (goal / GFS2_NBBY); + plong = (unsigned long *)(buffer + (goal / GFS2_NBBY)); bit = (goal % GFS2_NBBY) * GFS2_BIT_SIZE; - end = buffer + buflen; - alloc = (old_state == GFS2_BLKST_FREE) ? 0x55 : 0; - - while (byte < end) { - /* If we're looking for a free block we can eliminate all - bitmap settings with 0x55, which represents four data - blocks in a row. If we're looking for a data block, we can - eliminate 0x00 which corresponds to four free blocks. */ - if ((*byte & 0x55) == alloc) { - blk += (8 - bit) >> 1; - - bit = 0; - byte++; - + bitlong = bit; +#if BITS_PER_LONG == 32 + plong55 = 0x55555555; +#else + plong55 = 0x5555555555555555; +#endif + while (byte < buffer + buflen) { + + if (bitlong == 0 && old_state == 0 && *plong == plong55) { + plong++; + byte += sizeof(unsigned long); + blk += sizeof(unsigned long) * GFS2_NBBY; continue; } - if (((*byte >> bit) & GFS2_BIT_MASK) == old_state) return blk; - bit += GFS2_BIT_SIZE; if (bit >= 8) { bit = 0; byte++; } + bitlong += GFS2_BIT_SIZE; + if (bitlong >= sizeof(unsigned long) * 8) { + bitlong = 0; + plong++; + } blk++; } @@ -817,11 +819,9 @@ void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd) struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip) { - struct gfs2_alloc *al = &ip->i_alloc; - - /* FIXME: Should assert that the correct locks are held here... */ - memset(al, 0, sizeof(*al)); - return al; + BUG_ON(ip->i_alloc != NULL); + ip->i_alloc = kzalloc(sizeof(struct gfs2_alloc), GFP_KERNEL); + return ip->i_alloc; } /** @@ -1059,26 +1059,34 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked) struct inode *inode = NULL; struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_rgrpd *rgd, *begin = NULL; - struct gfs2_alloc *al = &ip->i_alloc; + struct gfs2_alloc *al = ip->i_alloc; int flags = LM_FLAG_TRY; int skipped = 0; int loops = 0; - int error; + int error, rg_locked; /* Try recently successful rgrps */ rgd = recent_rgrp_first(sdp, ip->i_last_rg_alloc); while (rgd) { - error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, - LM_FLAG_TRY, &al->al_rgd_gh); + rg_locked = 0; + + if (gfs2_glock_is_locked_by_me(rgd->rd_gl)) { + rg_locked = 1; + error = 0; + } else { + error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, + LM_FLAG_TRY, &al->al_rgd_gh); + } switch (error) { case 0: if (try_rgrp_fit(rgd, al)) goto out; if (rgd->rd_flags & GFS2_RDF_CHECK) inode = try_rgrp_unlink(rgd, last_unlinked); - gfs2_glock_dq_uninit(&al->al_rgd_gh); + if (!rg_locked) + gfs2_glock_dq_uninit(&al->al_rgd_gh); if (inode) return inode; rgd = recent_rgrp_next(rgd, 1); @@ -1098,15 +1106,23 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked) begin = rgd = forward_rgrp_get(sdp); for (;;) { - error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, flags, - &al->al_rgd_gh); + rg_locked = 0; + + if (gfs2_glock_is_locked_by_me(rgd->rd_gl)) { + rg_locked = 1; + error = 0; + } else { + error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, flags, + &al->al_rgd_gh); + } switch (error) { case 0: if (try_rgrp_fit(rgd, al)) goto out; if (rgd->rd_flags & GFS2_RDF_CHECK) inode = try_rgrp_unlink(rgd, last_unlinked); - gfs2_glock_dq_uninit(&al->al_rgd_gh); + if (!rg_locked) + gfs2_glock_dq_uninit(&al->al_rgd_gh); if (inode) return inode; break; @@ -1158,7 +1174,7 @@ out: int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); - struct gfs2_alloc *al = &ip->i_alloc; + struct gfs2_alloc *al = ip->i_alloc; struct inode *inode; int error = 0; u64 last_unlinked = NO_BLOCK; @@ -1204,7 +1220,7 @@ try_again: void gfs2_inplace_release(struct gfs2_inode *ip) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); - struct gfs2_alloc *al = &ip->i_alloc; + struct gfs2_alloc *al = ip->i_alloc; if (gfs2_assert_warn(sdp, al->al_alloced <= al->al_requested) == -1) fs_warn(sdp, "al_alloced = %u, al_requested = %u " @@ -1213,7 +1229,8 @@ void gfs2_inplace_release(struct gfs2_inode *ip) al->al_line); al->al_rgd = NULL; - gfs2_glock_dq_uninit(&al->al_rgd_gh); + if (al->al_rgd_gh.gh_gl) + gfs2_glock_dq_uninit(&al->al_rgd_gh); if (ip != GFS2_I(sdp->sd_rindex)) gfs2_glock_dq_uninit(&al->al_ri_gh); } @@ -1301,11 +1318,10 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, /* The GFS2_BLKST_UNLINKED state doesn't apply to the clone bitmaps, so we must search the originals for that. */ if (old_state != GFS2_BLKST_UNLINKED && bi->bi_clone) - blk = gfs2_bitfit(rgd, bi->bi_clone + bi->bi_offset, + blk = gfs2_bitfit(bi->bi_clone + bi->bi_offset, bi->bi_len, goal, old_state); else - blk = gfs2_bitfit(rgd, - bi->bi_bh->b_data + bi->bi_offset, + blk = gfs2_bitfit(bi->bi_bh->b_data + bi->bi_offset, bi->bi_len, goal, old_state); if (blk != BFITNOENT) break; @@ -1394,7 +1410,7 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart, u64 gfs2_alloc_data(struct gfs2_inode *ip) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); - struct gfs2_alloc *al = &ip->i_alloc; + struct gfs2_alloc *al = ip->i_alloc; struct gfs2_rgrpd *rgd = al->al_rgd; u32 goal, blk; u64 block; @@ -1439,7 +1455,7 @@ u64 gfs2_alloc_data(struct gfs2_inode *ip) u64 gfs2_alloc_meta(struct gfs2_inode *ip) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); - struct gfs2_alloc *al = &ip->i_alloc; + struct gfs2_alloc *al = ip->i_alloc; struct gfs2_rgrpd *rgd = al->al_rgd; u32 goal, blk; u64 block; @@ -1485,7 +1501,7 @@ u64 gfs2_alloc_meta(struct gfs2_inode *ip) u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation) { struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); - struct gfs2_alloc *al = &dip->i_alloc; + struct gfs2_alloc *al = dip->i_alloc; struct gfs2_rgrpd *rgd = al->al_rgd; u32 blk; u64 block; diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index b4c6adfc6f2e..149bb161f4b6 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h @@ -32,7 +32,9 @@ void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd); struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip); static inline void gfs2_alloc_put(struct gfs2_inode *ip) { - return; /* So we can see where ip->i_alloc is used */ + BUG_ON(ip->i_alloc == NULL); + kfree(ip->i_alloc); + ip->i_alloc = NULL; } int gfs2_inplace_reserve_i(struct gfs2_inode *ip, diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index dd3e737f528e..ef0562c3bc71 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -1,6 +1,6 @@ /* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions @@ -51,13 +51,9 @@ void gfs2_tune_init(struct gfs2_tune *gt) { spin_lock_init(>->gt_spin); - gt->gt_ilimit = 100; - gt->gt_ilimit_tries = 3; - gt->gt_ilimit_min = 1; gt->gt_demote_secs = 300; gt->gt_incore_log_blocks = 1024; gt->gt_log_flush_secs = 60; - gt->gt_jindex_refresh_secs = 60; gt->gt_recoverd_secs = 60; gt->gt_logd_secs = 1; gt->gt_quotad_secs = 5; @@ -71,10 +67,8 @@ void gfs2_tune_init(struct gfs2_tune *gt) gt->gt_new_files_jdata = 0; gt->gt_new_files_directio = 0; gt->gt_max_readahead = 1 << 18; - gt->gt_lockdump_size = 131072; gt->gt_stall_secs = 600; gt->gt_complain_secs = 10; - gt->gt_reclaim_limit = 5000; gt->gt_statfs_quantum = 30; gt->gt_statfs_slow = 0; } @@ -393,6 +387,7 @@ int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh) if (!jd) break; + INIT_LIST_HEAD(&jd->extent_list); jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1, NULL); if (!jd->jd_inode || IS_ERR(jd->jd_inode)) { if (!jd->jd_inode) @@ -422,8 +417,9 @@ int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh) void gfs2_jindex_free(struct gfs2_sbd *sdp) { - struct list_head list; + struct list_head list, *head; struct gfs2_jdesc *jd; + struct gfs2_journal_extent *jext; spin_lock(&sdp->sd_jindex_spin); list_add(&list, &sdp->sd_jindex_list); @@ -433,6 +429,14 @@ void gfs2_jindex_free(struct gfs2_sbd *sdp) while (!list_empty(&list)) { jd = list_entry(list.next, struct gfs2_jdesc, jd_list); + head = &jd->extent_list; + while (!list_empty(head)) { + jext = list_entry(head->next, + struct gfs2_journal_extent, + extent_list); + list_del(&jext->extent_list); + kfree(jext); + } list_del(&jd->jd_list); iput(jd->jd_inode); kfree(jd); @@ -543,7 +547,6 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp) if (error) return error; - gfs2_meta_cache_flush(ip); j_gl->gl_ops->go_inval(j_gl, DIO_METADATA); error = gfs2_find_jhead(sdp->sd_jdesc, &head); @@ -686,9 +689,7 @@ void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free, if (error) return; - mutex_lock(&sdp->sd_statfs_mutex); gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1); - mutex_unlock(&sdp->sd_statfs_mutex); spin_lock(&sdp->sd_statfs_spin); l_sc->sc_total += total; @@ -736,9 +737,7 @@ int gfs2_statfs_sync(struct gfs2_sbd *sdp) if (error) goto out_bh2; - mutex_lock(&sdp->sd_statfs_mutex); gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1); - mutex_unlock(&sdp->sd_statfs_mutex); spin_lock(&sdp->sd_statfs_spin); m_sc->sc_total += l_sc->sc_total; diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index 06e0b7768d97..eaa3b7b2f99e 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -32,7 +32,8 @@ spinlock_t gfs2_sys_margs_lock; static ssize_t id_show(struct gfs2_sbd *sdp, char *buf) { - return snprintf(buf, PAGE_SIZE, "%s\n", sdp->sd_vfs->s_id); + return snprintf(buf, PAGE_SIZE, "%u:%u\n", + MAJOR(sdp->sd_vfs->s_dev), MINOR(sdp->sd_vfs->s_dev)); } static ssize_t fsname_show(struct gfs2_sbd *sdp, char *buf) @@ -221,9 +222,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 @@ -427,13 +426,11 @@ TUNE_ATTR_2(name, name##_store) TUNE_ATTR(demote_secs, 0); TUNE_ATTR(incore_log_blocks, 0); TUNE_ATTR(log_flush_secs, 0); -TUNE_ATTR(jindex_refresh_secs, 0); TUNE_ATTR(quota_warn_period, 0); TUNE_ATTR(quota_quantum, 0); TUNE_ATTR(atime_quantum, 0); TUNE_ATTR(max_readahead, 0); TUNE_ATTR(complain_secs, 0); -TUNE_ATTR(reclaim_limit, 0); TUNE_ATTR(statfs_slow, 0); TUNE_ATTR(new_files_jdata, 0); TUNE_ATTR(new_files_directio, 0); @@ -450,13 +447,11 @@ static struct attribute *tune_attrs[] = { &tune_attr_demote_secs.attr, &tune_attr_incore_log_blocks.attr, &tune_attr_log_flush_secs.attr, - &tune_attr_jindex_refresh_secs.attr, &tune_attr_quota_warn_period.attr, &tune_attr_quota_quantum.attr, &tune_attr_atime_quantum.attr, &tune_attr_max_readahead.attr, &tune_attr_complain_secs.attr, - &tune_attr_reclaim_limit.attr, &tune_attr_statfs_slow.attr, &tune_attr_quota_simul_sync.attr, &tune_attr_quota_cache_secs.attr, @@ -495,14 +490,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 +512,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 +522,7 @@ fail_counters: 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 +534,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/gfs2/trans.c b/fs/gfs2/trans.c index 717983e2c2ae..73e5d92a657c 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -114,11 +114,6 @@ void gfs2_trans_end(struct gfs2_sbd *sdp) gfs2_log_flush(sdp, NULL); } -void gfs2_trans_add_gl(struct gfs2_glock *gl) -{ - lops_add(gl->gl_sbd, &gl->gl_le); -} - /** * gfs2_trans_add_bh - Add a to-be-modified buffer to the current transaction * @gl: the glock the buffer belongs to diff --git a/fs/gfs2/trans.h b/fs/gfs2/trans.h index 043d5f4b9c4c..e826f0dab80a 100644 --- a/fs/gfs2/trans.h +++ b/fs/gfs2/trans.h @@ -30,7 +30,6 @@ int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks, void gfs2_trans_end(struct gfs2_sbd *sdp); -void gfs2_trans_add_gl(struct gfs2_glock *gl); void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta); void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd); void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno); diff --git a/fs/namespace.c b/fs/namespace.c index 06083885b21e..61bf376e29e8 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 a4882c8df945..23c732f27529 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 64f6f378fd09..a4b07730b2e1 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 722e12e5acc7..739da701ae7b 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 f281cc6584b0..4948d9bc405d 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 4045bdcc4b33..8acf82bba44c 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 3eac20c63c41..5f66c4466151 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 7b74b60a68a4..fb7171b1bd22 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/crypto/aead.h b/include/crypto/aead.h new file mode 100644 index 000000000000..0edf949f6369 --- /dev/null +++ b/include/crypto/aead.h @@ -0,0 +1,105 @@ +/* + * AEAD: Authenticated Encryption with Associated Data + * + * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au> + * + * 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. + * + */ + +#ifndef _CRYPTO_AEAD_H +#define _CRYPTO_AEAD_H + +#include <linux/crypto.h> +#include <linux/kernel.h> +#include <linux/slab.h> + +/** + * struct aead_givcrypt_request - AEAD request with IV generation + * @seq: Sequence number for IV generation + * @giv: Space for generated IV + * @areq: The AEAD request itself + */ +struct aead_givcrypt_request { + u64 seq; + u8 *giv; + + struct aead_request areq; +}; + +static inline struct crypto_aead *aead_givcrypt_reqtfm( + struct aead_givcrypt_request *req) +{ + return crypto_aead_reqtfm(&req->areq); +} + +static inline int crypto_aead_givencrypt(struct aead_givcrypt_request *req) +{ + struct aead_tfm *crt = crypto_aead_crt(aead_givcrypt_reqtfm(req)); + return crt->givencrypt(req); +}; + +static inline int crypto_aead_givdecrypt(struct aead_givcrypt_request *req) +{ + struct aead_tfm *crt = crypto_aead_crt(aead_givcrypt_reqtfm(req)); + return crt->givdecrypt(req); +}; + +static inline void aead_givcrypt_set_tfm(struct aead_givcrypt_request *req, + struct crypto_aead *tfm) +{ + req->areq.base.tfm = crypto_aead_tfm(tfm); +} + +static inline struct aead_givcrypt_request *aead_givcrypt_alloc( + struct crypto_aead *tfm, gfp_t gfp) +{ + struct aead_givcrypt_request *req; + + req = kmalloc(sizeof(struct aead_givcrypt_request) + + crypto_aead_reqsize(tfm), gfp); + + if (likely(req)) + aead_givcrypt_set_tfm(req, tfm); + + return req; +} + +static inline void aead_givcrypt_free(struct aead_givcrypt_request *req) +{ + kfree(req); +} + +static inline void aead_givcrypt_set_callback( + struct aead_givcrypt_request *req, u32 flags, + crypto_completion_t complete, void *data) +{ + aead_request_set_callback(&req->areq, flags, complete, data); +} + +static inline void aead_givcrypt_set_crypt(struct aead_givcrypt_request *req, + struct scatterlist *src, + struct scatterlist *dst, + unsigned int nbytes, void *iv) +{ + aead_request_set_crypt(&req->areq, src, dst, nbytes, iv); +} + +static inline void aead_givcrypt_set_assoc(struct aead_givcrypt_request *req, + struct scatterlist *assoc, + unsigned int assoclen) +{ + aead_request_set_assoc(&req->areq, assoc, assoclen); +} + +static inline void aead_givcrypt_set_giv(struct aead_givcrypt_request *req, + u8 *giv, u64 seq) +{ + req->giv = giv; + req->seq = seq; +} + +#endif /* _CRYPTO_AEAD_H */ diff --git a/include/crypto/aes.h b/include/crypto/aes.h new file mode 100644 index 000000000000..d480b76715a8 --- /dev/null +++ b/include/crypto/aes.h @@ -0,0 +1,31 @@ +/* + * Common values for AES algorithms + */ + +#ifndef _CRYPTO_AES_H +#define _CRYPTO_AES_H + +#include <linux/types.h> +#include <linux/crypto.h> + +#define AES_MIN_KEY_SIZE 16 +#define AES_MAX_KEY_SIZE 32 +#define AES_KEYSIZE_128 16 +#define AES_KEYSIZE_192 24 +#define AES_KEYSIZE_256 32 +#define AES_BLOCK_SIZE 16 + +struct crypto_aes_ctx { + u32 key_length; + u32 key_enc[60]; + u32 key_dec[60]; +}; + +extern u32 crypto_ft_tab[4][256]; +extern u32 crypto_fl_tab[4][256]; +extern u32 crypto_it_tab[4][256]; +extern u32 crypto_il_tab[4][256]; + +int crypto_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, + unsigned int key_len); +#endif diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h index b9b05d399d2b..60d06e784be3 100644 --- a/include/crypto/algapi.h +++ b/include/crypto/algapi.h @@ -111,8 +111,15 @@ void crypto_drop_spawn(struct crypto_spawn *spawn); struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type, u32 mask); +static inline void crypto_set_spawn(struct crypto_spawn *spawn, + struct crypto_instance *inst) +{ + spawn->inst = inst; +} + struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb); int crypto_check_attr_type(struct rtattr **tb, u32 type); +const char *crypto_attr_alg_name(struct rtattr *rta); struct crypto_alg *crypto_attr_alg(struct rtattr *rta, u32 type, u32 mask); int crypto_attr_u32(struct rtattr *rta, u32 *num); struct crypto_instance *crypto_alloc_instance(const char *name, @@ -124,6 +131,10 @@ int crypto_enqueue_request(struct crypto_queue *queue, struct crypto_async_request *crypto_dequeue_request(struct crypto_queue *queue); int crypto_tfm_in_queue(struct crypto_queue *queue, struct crypto_tfm *tfm); +/* These functions require the input/output to be aligned as u32. */ +void crypto_inc(u8 *a, unsigned int size); +void crypto_xor(u8 *dst, const u8 *src, unsigned int size); + int blkcipher_walk_done(struct blkcipher_desc *desc, struct blkcipher_walk *walk, int err); int blkcipher_walk_virt(struct blkcipher_desc *desc, @@ -187,20 +198,11 @@ static inline struct crypto_instance *crypto_aead_alg_instance( return crypto_tfm_alg_instance(&aead->base); } -static inline struct crypto_ablkcipher *crypto_spawn_ablkcipher( - struct crypto_spawn *spawn) -{ - u32 type = CRYPTO_ALG_TYPE_BLKCIPHER; - u32 mask = CRYPTO_ALG_TYPE_MASK; - - return __crypto_ablkcipher_cast(crypto_spawn_tfm(spawn, type, mask)); -} - static inline struct crypto_blkcipher *crypto_spawn_blkcipher( struct crypto_spawn *spawn) { u32 type = CRYPTO_ALG_TYPE_BLKCIPHER; - u32 mask = CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC; + u32 mask = CRYPTO_ALG_TYPE_MASK; return __crypto_blkcipher_cast(crypto_spawn_tfm(spawn, type, mask)); } @@ -303,5 +305,14 @@ static inline struct crypto_alg *crypto_get_attr_alg(struct rtattr **tb, return crypto_attr_alg(tb[1], type, mask); } +/* + * Returns CRYPTO_ALG_ASYNC if type/mask requires the use of sync algorithms. + * Otherwise returns zero. + */ +static inline int crypto_requires_sync(u32 type, u32 mask) +{ + return (type ^ CRYPTO_ALG_ASYNC) & mask & CRYPTO_ALG_ASYNC; +} + #endif /* _CRYPTO_ALGAPI_H */ diff --git a/include/crypto/authenc.h b/include/crypto/authenc.h new file mode 100644 index 000000000000..e47b044929a8 --- /dev/null +++ b/include/crypto/authenc.h @@ -0,0 +1,27 @@ +/* + * Authenc: Simple AEAD wrapper for IPsec + * + * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au> + * + * 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. + * + */ +#ifndef _CRYPTO_AUTHENC_H +#define _CRYPTO_AUTHENC_H + +#include <linux/types.h> + +enum { + CRYPTO_AUTHENC_KEYA_UNSPEC, + CRYPTO_AUTHENC_KEYA_PARAM, +}; + +struct crypto_authenc_key_param { + __be32 enckeylen; +}; + +#endif /* _CRYPTO_AUTHENC_H */ + diff --git a/include/crypto/ctr.h b/include/crypto/ctr.h new file mode 100644 index 000000000000..4180fc080e3b --- /dev/null +++ b/include/crypto/ctr.h @@ -0,0 +1,20 @@ +/* + * CTR: Counter mode + * + * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au> + * + * 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. + * + */ + +#ifndef _CRYPTO_CTR_H +#define _CRYPTO_CTR_H + +#define CTR_RFC3686_NONCE_SIZE 4 +#define CTR_RFC3686_IV_SIZE 8 +#define CTR_RFC3686_BLOCK_SIZE 16 + +#endif /* _CRYPTO_CTR_H */ diff --git a/include/crypto/des.h b/include/crypto/des.h new file mode 100644 index 000000000000..2971c6304ade --- /dev/null +++ b/include/crypto/des.h @@ -0,0 +1,19 @@ +/* + * DES & Triple DES EDE Cipher Algorithms. + */ + +#ifndef __CRYPTO_DES_H +#define __CRYPTO_DES_H + +#define DES_KEY_SIZE 8 +#define DES_EXPKEY_WORDS 32 +#define DES_BLOCK_SIZE 8 + +#define DES3_EDE_KEY_SIZE (3 * DES_KEY_SIZE) +#define DES3_EDE_EXPKEY_WORDS (3 * DES_EXPKEY_WORDS) +#define DES3_EDE_BLOCK_SIZE DES_BLOCK_SIZE + + +extern unsigned long des_ekey(u32 *pe, const u8 *k); + +#endif /* __CRYPTO_DES_H */ diff --git a/include/crypto/internal/aead.h b/include/crypto/internal/aead.h new file mode 100644 index 000000000000..d838c945575a --- /dev/null +++ b/include/crypto/internal/aead.h @@ -0,0 +1,80 @@ +/* + * AEAD: Authenticated Encryption with Associated Data + * + * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au> + * + * 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. + * + */ + +#ifndef _CRYPTO_INTERNAL_AEAD_H +#define _CRYPTO_INTERNAL_AEAD_H + +#include <crypto/aead.h> +#include <crypto/algapi.h> +#include <linux/types.h> + +struct rtattr; + +struct crypto_aead_spawn { + struct crypto_spawn base; +}; + +extern const struct crypto_type crypto_nivaead_type; + +static inline void crypto_set_aead_spawn( + struct crypto_aead_spawn *spawn, struct crypto_instance *inst) +{ + crypto_set_spawn(&spawn->base, inst); +} + +int crypto_grab_aead(struct crypto_aead_spawn *spawn, const char *name, + u32 type, u32 mask); + +static inline void crypto_drop_aead(struct crypto_aead_spawn *spawn) +{ + crypto_drop_spawn(&spawn->base); +} + +static inline struct crypto_alg *crypto_aead_spawn_alg( + struct crypto_aead_spawn *spawn) +{ + return spawn->base.alg; +} + +static inline struct crypto_aead *crypto_spawn_aead( + struct crypto_aead_spawn *spawn) +{ + return __crypto_aead_cast( + crypto_spawn_tfm(&spawn->base, CRYPTO_ALG_TYPE_AEAD, + CRYPTO_ALG_TYPE_MASK)); +} + +struct crypto_instance *aead_geniv_alloc(struct crypto_template *tmpl, + struct rtattr **tb, u32 type, + u32 mask); +void aead_geniv_free(struct crypto_instance *inst); +int aead_geniv_init(struct crypto_tfm *tfm); +void aead_geniv_exit(struct crypto_tfm *tfm); + +static inline struct crypto_aead *aead_geniv_base(struct crypto_aead *geniv) +{ + return crypto_aead_crt(geniv)->base; +} + +static inline void *aead_givcrypt_reqctx(struct aead_givcrypt_request *req) +{ + return aead_request_ctx(&req->areq); +} + +static inline void aead_givcrypt_complete(struct aead_givcrypt_request *req, + int err) +{ + aead_request_complete(&req->areq, err); +} + +#endif /* _CRYPTO_INTERNAL_AEAD_H */ + diff --git a/include/crypto/internal/skcipher.h b/include/crypto/internal/skcipher.h new file mode 100644 index 000000000000..2ba42cd7d6aa --- /dev/null +++ b/include/crypto/internal/skcipher.h @@ -0,0 +1,110 @@ +/* + * Symmetric key ciphers. + * + * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au> + * + * 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. + * + */ + +#ifndef _CRYPTO_INTERNAL_SKCIPHER_H +#define _CRYPTO_INTERNAL_SKCIPHER_H + +#include <crypto/algapi.h> +#include <crypto/skcipher.h> +#include <linux/types.h> + +struct rtattr; + +struct crypto_skcipher_spawn { + struct crypto_spawn base; +}; + +extern const struct crypto_type crypto_givcipher_type; + +static inline void crypto_set_skcipher_spawn( + struct crypto_skcipher_spawn *spawn, struct crypto_instance *inst) +{ + crypto_set_spawn(&spawn->base, inst); +} + +int crypto_grab_skcipher(struct crypto_skcipher_spawn *spawn, const char *name, + u32 type, u32 mask); + +static inline void crypto_drop_skcipher(struct crypto_skcipher_spawn *spawn) +{ + crypto_drop_spawn(&spawn->base); +} + +static inline struct crypto_alg *crypto_skcipher_spawn_alg( + struct crypto_skcipher_spawn *spawn) +{ + return spawn->base.alg; +} + +static inline struct crypto_ablkcipher *crypto_spawn_skcipher( + struct crypto_skcipher_spawn *spawn) +{ + return __crypto_ablkcipher_cast( + crypto_spawn_tfm(&spawn->base, crypto_skcipher_type(0), + crypto_skcipher_mask(0))); +} + +int skcipher_null_givencrypt(struct skcipher_givcrypt_request *req); +int skcipher_null_givdecrypt(struct skcipher_givcrypt_request *req); +const char *crypto_default_geniv(const struct crypto_alg *alg); + +struct crypto_instance *skcipher_geniv_alloc(struct crypto_template *tmpl, + struct rtattr **tb, u32 type, + u32 mask); +void skcipher_geniv_free(struct crypto_instance *inst); +int skcipher_geniv_init(struct crypto_tfm *tfm); +void skcipher_geniv_exit(struct crypto_tfm *tfm); + +static inline struct crypto_ablkcipher *skcipher_geniv_cipher( + struct crypto_ablkcipher *geniv) +{ + return crypto_ablkcipher_crt(geniv)->base; +} + +static inline int skcipher_enqueue_givcrypt( + struct crypto_queue *queue, struct skcipher_givcrypt_request *request) +{ + return ablkcipher_enqueue_request(queue, &request->creq); +} + +static inline struct skcipher_givcrypt_request *skcipher_dequeue_givcrypt( + struct crypto_queue *queue) +{ + return container_of(ablkcipher_dequeue_request(queue), + struct skcipher_givcrypt_request, creq); +} + +static inline void *skcipher_givcrypt_reqctx( + struct skcipher_givcrypt_request *req) +{ + return ablkcipher_request_ctx(&req->creq); +} + +static inline void ablkcipher_request_complete(struct ablkcipher_request *req, + int err) +{ + req->base.complete(&req->base, err); +} + +static inline void skcipher_givcrypt_complete( + struct skcipher_givcrypt_request *req, int err) +{ + ablkcipher_request_complete(&req->creq, err); +} + +static inline u32 ablkcipher_request_flags(struct ablkcipher_request *req) +{ + return req->base.flags; +} + +#endif /* _CRYPTO_INTERNAL_SKCIPHER_H */ + diff --git a/crypto/scatterwalk.h b/include/crypto/scatterwalk.h index 87ed681cceba..224658b8d806 100644 --- a/crypto/scatterwalk.h +++ b/include/crypto/scatterwalk.h @@ -1,9 +1,10 @@ /* - * Cryptographic API. + * Cryptographic scatter and gather helpers. * * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> * Copyright (c) 2002 Adam J. Richter <adam@yggdrasil.com> * Copyright (c) 2004 Jean-Luc Cooke <jlcooke@certainkey.com> + * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au> * * 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 @@ -15,14 +16,52 @@ #ifndef _CRYPTO_SCATTERWALK_H #define _CRYPTO_SCATTERWALK_H +#include <asm/kmap_types.h> +#include <crypto/algapi.h> +#include <linux/hardirq.h> +#include <linux/highmem.h> +#include <linux/kernel.h> #include <linux/mm.h> #include <linux/scatterlist.h> +#include <linux/sched.h> -#include "internal.h" +static inline enum km_type crypto_kmap_type(int out) +{ + enum km_type type; + + if (in_softirq()) + type = out * (KM_SOFTIRQ1 - KM_SOFTIRQ0) + KM_SOFTIRQ0; + else + type = out * (KM_USER1 - KM_USER0) + KM_USER0; + + return type; +} + +static inline void *crypto_kmap(struct page *page, int out) +{ + return kmap_atomic(page, crypto_kmap_type(out)); +} + +static inline void crypto_kunmap(void *vaddr, int out) +{ + kunmap_atomic(vaddr, crypto_kmap_type(out)); +} + +static inline void crypto_yield(u32 flags) +{ + if (flags & CRYPTO_TFM_REQ_MAY_SLEEP) + cond_resched(); +} + +static inline void scatterwalk_sg_chain(struct scatterlist *sg1, int num, + struct scatterlist *sg2) +{ + sg_set_page(&sg1[num - 1], (void *)sg2, 0, 0); +} static inline struct scatterlist *scatterwalk_sg_next(struct scatterlist *sg) { - return (++sg)->length ? sg : (void *) sg_page(sg); + return (++sg)->length ? sg : (void *)sg_page(sg); } static inline unsigned long scatterwalk_samebuf(struct scatter_walk *walk_in, diff --git a/include/crypto/sha.h b/include/crypto/sha.h index 0686e1f7a24b..c0ccc2b1a2d8 100644 --- a/include/crypto/sha.h +++ b/include/crypto/sha.h @@ -8,6 +8,9 @@ #define SHA1_DIGEST_SIZE 20 #define SHA1_BLOCK_SIZE 64 +#define SHA224_DIGEST_SIZE 28 +#define SHA224_BLOCK_SIZE 64 + #define SHA256_DIGEST_SIZE 32 #define SHA256_BLOCK_SIZE 64 @@ -23,6 +26,15 @@ #define SHA1_H3 0x10325476UL #define SHA1_H4 0xc3d2e1f0UL +#define SHA224_H0 0xc1059ed8UL +#define SHA224_H1 0x367cd507UL +#define SHA224_H2 0x3070dd17UL +#define SHA224_H3 0xf70e5939UL +#define SHA224_H4 0xffc00b31UL +#define SHA224_H5 0x68581511UL +#define SHA224_H6 0x64f98fa7UL +#define SHA224_H7 0xbefa4fa4UL + #define SHA256_H0 0x6a09e667UL #define SHA256_H1 0xbb67ae85UL #define SHA256_H2 0x3c6ef372UL diff --git a/include/crypto/skcipher.h b/include/crypto/skcipher.h new file mode 100644 index 000000000000..25fd6126522d --- /dev/null +++ b/include/crypto/skcipher.h @@ -0,0 +1,110 @@ +/* + * Symmetric key ciphers. + * + * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au> + * + * 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. + * + */ + +#ifndef _CRYPTO_SKCIPHER_H +#define _CRYPTO_SKCIPHER_H + +#include <linux/crypto.h> +#include <linux/kernel.h> +#include <linux/slab.h> + +/** + * struct skcipher_givcrypt_request - Crypto request with IV generation + * @seq: Sequence number for IV generation + * @giv: Space for generated IV + * @creq: The crypto request itself + */ +struct skcipher_givcrypt_request { + u64 seq; + u8 *giv; + + struct ablkcipher_request creq; +}; + +static inline struct crypto_ablkcipher *skcipher_givcrypt_reqtfm( + struct skcipher_givcrypt_request *req) +{ + return crypto_ablkcipher_reqtfm(&req->creq); +} + +static inline int crypto_skcipher_givencrypt( + struct skcipher_givcrypt_request *req) +{ + struct ablkcipher_tfm *crt = + crypto_ablkcipher_crt(skcipher_givcrypt_reqtfm(req)); + return crt->givencrypt(req); +}; + +static inline int crypto_skcipher_givdecrypt( + struct skcipher_givcrypt_request *req) +{ + struct ablkcipher_tfm *crt = + crypto_ablkcipher_crt(skcipher_givcrypt_reqtfm(req)); + return crt->givdecrypt(req); +}; + +static inline void skcipher_givcrypt_set_tfm( + struct skcipher_givcrypt_request *req, struct crypto_ablkcipher *tfm) +{ + req->creq.base.tfm = crypto_ablkcipher_tfm(tfm); +} + +static inline struct skcipher_givcrypt_request *skcipher_givcrypt_cast( + struct crypto_async_request *req) +{ + return container_of(ablkcipher_request_cast(req), + struct skcipher_givcrypt_request, creq); +} + +static inline struct skcipher_givcrypt_request *skcipher_givcrypt_alloc( + struct crypto_ablkcipher *tfm, gfp_t gfp) +{ + struct skcipher_givcrypt_request *req; + + req = kmalloc(sizeof(struct skcipher_givcrypt_request) + + crypto_ablkcipher_reqsize(tfm), gfp); + + if (likely(req)) + skcipher_givcrypt_set_tfm(req, tfm); + + return req; +} + +static inline void skcipher_givcrypt_free(struct skcipher_givcrypt_request *req) +{ + kfree(req); +} + +static inline void skcipher_givcrypt_set_callback( + struct skcipher_givcrypt_request *req, u32 flags, + crypto_completion_t complete, void *data) +{ + ablkcipher_request_set_callback(&req->creq, flags, complete, data); +} + +static inline void skcipher_givcrypt_set_crypt( + struct skcipher_givcrypt_request *req, + struct scatterlist *src, struct scatterlist *dst, + unsigned int nbytes, void *iv) +{ + ablkcipher_request_set_crypt(&req->creq, src, dst, nbytes, iv); +} + +static inline void skcipher_givcrypt_set_giv( + struct skcipher_givcrypt_request *req, u8 *giv, u64 seq) +{ + req->giv = giv; + req->seq = seq; +} + +#endif /* _CRYPTO_SKCIPHER_H */ + diff --git a/include/linux/crypto.h b/include/linux/crypto.h index f3110ebe894a..5e02d1b46370 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -33,10 +33,13 @@ #define CRYPTO_ALG_TYPE_DIGEST 0x00000002 #define CRYPTO_ALG_TYPE_HASH 0x00000003 #define CRYPTO_ALG_TYPE_BLKCIPHER 0x00000004 -#define CRYPTO_ALG_TYPE_COMPRESS 0x00000005 -#define CRYPTO_ALG_TYPE_AEAD 0x00000006 +#define CRYPTO_ALG_TYPE_ABLKCIPHER 0x00000005 +#define CRYPTO_ALG_TYPE_GIVCIPHER 0x00000006 +#define CRYPTO_ALG_TYPE_COMPRESS 0x00000008 +#define CRYPTO_ALG_TYPE_AEAD 0x00000009 #define CRYPTO_ALG_TYPE_HASH_MASK 0x0000000e +#define CRYPTO_ALG_TYPE_BLKCIPHER_MASK 0x0000000c #define CRYPTO_ALG_LARVAL 0x00000010 #define CRYPTO_ALG_DEAD 0x00000020 @@ -50,6 +53,12 @@ #define CRYPTO_ALG_NEED_FALLBACK 0x00000100 /* + * This bit is set for symmetric key ciphers that have already been wrapped + * with a generic IV generator to prevent them from being wrapped again. + */ +#define CRYPTO_ALG_GENIV 0x00000200 + +/* * Transform masks and values (for crt_flags). */ #define CRYPTO_TFM_REQ_MASK 0x000fff00 @@ -81,13 +90,11 @@ #define CRYPTO_MINALIGN ARCH_KMALLOC_MINALIGN #elif defined(ARCH_SLAB_MINALIGN) #define CRYPTO_MINALIGN ARCH_SLAB_MINALIGN +#else +#define CRYPTO_MINALIGN __alignof__(unsigned long long) #endif -#ifdef CRYPTO_MINALIGN #define CRYPTO_MINALIGN_ATTR __attribute__ ((__aligned__(CRYPTO_MINALIGN))) -#else -#define CRYPTO_MINALIGN_ATTR -#endif struct scatterlist; struct crypto_ablkcipher; @@ -97,6 +104,8 @@ struct crypto_blkcipher; struct crypto_hash; struct crypto_tfm; struct crypto_type; +struct aead_givcrypt_request; +struct skcipher_givcrypt_request; typedef void (*crypto_completion_t)(struct crypto_async_request *req, int err); @@ -176,6 +185,10 @@ struct ablkcipher_alg { unsigned int keylen); int (*encrypt)(struct ablkcipher_request *req); int (*decrypt)(struct ablkcipher_request *req); + int (*givencrypt)(struct skcipher_givcrypt_request *req); + int (*givdecrypt)(struct skcipher_givcrypt_request *req); + + const char *geniv; unsigned int min_keysize; unsigned int max_keysize; @@ -185,11 +198,16 @@ struct ablkcipher_alg { struct aead_alg { int (*setkey)(struct crypto_aead *tfm, const u8 *key, unsigned int keylen); + int (*setauthsize)(struct crypto_aead *tfm, unsigned int authsize); int (*encrypt)(struct aead_request *req); int (*decrypt)(struct aead_request *req); + int (*givencrypt)(struct aead_givcrypt_request *req); + int (*givdecrypt)(struct aead_givcrypt_request *req); + + const char *geniv; unsigned int ivsize; - unsigned int authsize; + unsigned int maxauthsize; }; struct blkcipher_alg { @@ -202,6 +220,8 @@ struct blkcipher_alg { struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes); + const char *geniv; + unsigned int min_keysize; unsigned int max_keysize; unsigned int ivsize; @@ -317,6 +337,11 @@ struct ablkcipher_tfm { unsigned int keylen); int (*encrypt)(struct ablkcipher_request *req); int (*decrypt)(struct ablkcipher_request *req); + int (*givencrypt)(struct skcipher_givcrypt_request *req); + int (*givdecrypt)(struct skcipher_givcrypt_request *req); + + struct crypto_ablkcipher *base; + unsigned int ivsize; unsigned int reqsize; }; @@ -326,6 +351,11 @@ struct aead_tfm { unsigned int keylen); int (*encrypt)(struct aead_request *req); int (*decrypt)(struct aead_request *req); + int (*givencrypt)(struct aead_givcrypt_request *req); + int (*givdecrypt)(struct aead_givcrypt_request *req); + + struct crypto_aead *base; + unsigned int ivsize; unsigned int authsize; unsigned int reqsize; @@ -525,17 +555,23 @@ static inline struct crypto_ablkcipher *__crypto_ablkcipher_cast( return (struct crypto_ablkcipher *)tfm; } -static inline struct crypto_ablkcipher *crypto_alloc_ablkcipher( - const char *alg_name, u32 type, u32 mask) +static inline u32 crypto_skcipher_type(u32 type) { - type &= ~CRYPTO_ALG_TYPE_MASK; + type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV); type |= CRYPTO_ALG_TYPE_BLKCIPHER; - mask |= CRYPTO_ALG_TYPE_MASK; + return type; +} - return __crypto_ablkcipher_cast( - crypto_alloc_base(alg_name, type, mask)); +static inline u32 crypto_skcipher_mask(u32 mask) +{ + mask &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV); + mask |= CRYPTO_ALG_TYPE_BLKCIPHER_MASK; + return mask; } +struct crypto_ablkcipher *crypto_alloc_ablkcipher(const char *alg_name, + u32 type, u32 mask); + static inline struct crypto_tfm *crypto_ablkcipher_tfm( struct crypto_ablkcipher *tfm) { @@ -550,11 +586,8 @@ static inline void crypto_free_ablkcipher(struct crypto_ablkcipher *tfm) static inline int crypto_has_ablkcipher(const char *alg_name, u32 type, u32 mask) { - type &= ~CRYPTO_ALG_TYPE_MASK; - type |= CRYPTO_ALG_TYPE_BLKCIPHER; - mask |= CRYPTO_ALG_TYPE_MASK; - - return crypto_has_alg(alg_name, type, mask); + return crypto_has_alg(alg_name, crypto_skcipher_type(type), + crypto_skcipher_mask(mask)); } static inline struct ablkcipher_tfm *crypto_ablkcipher_crt( @@ -601,7 +634,9 @@ static inline void crypto_ablkcipher_clear_flags(struct crypto_ablkcipher *tfm, static inline int crypto_ablkcipher_setkey(struct crypto_ablkcipher *tfm, const u8 *key, unsigned int keylen) { - return crypto_ablkcipher_crt(tfm)->setkey(tfm, key, keylen); + struct ablkcipher_tfm *crt = crypto_ablkcipher_crt(tfm); + + return crt->setkey(crt->base, key, keylen); } static inline struct crypto_ablkcipher *crypto_ablkcipher_reqtfm( @@ -633,7 +668,7 @@ static inline unsigned int crypto_ablkcipher_reqsize( static inline void ablkcipher_request_set_tfm( struct ablkcipher_request *req, struct crypto_ablkcipher *tfm) { - req->base.tfm = crypto_ablkcipher_tfm(tfm); + req->base.tfm = crypto_ablkcipher_tfm(crypto_ablkcipher_crt(tfm)->base); } static inline struct ablkcipher_request *ablkcipher_request_cast( @@ -686,15 +721,7 @@ static inline struct crypto_aead *__crypto_aead_cast(struct crypto_tfm *tfm) return (struct crypto_aead *)tfm; } -static inline struct crypto_aead *crypto_alloc_aead(const char *alg_name, - u32 type, u32 mask) -{ - type &= ~CRYPTO_ALG_TYPE_MASK; - type |= CRYPTO_ALG_TYPE_AEAD; - mask |= CRYPTO_ALG_TYPE_MASK; - - return __crypto_aead_cast(crypto_alloc_base(alg_name, type, mask)); -} +struct crypto_aead *crypto_alloc_aead(const char *alg_name, u32 type, u32 mask); static inline struct crypto_tfm *crypto_aead_tfm(struct crypto_aead *tfm) { @@ -749,9 +776,13 @@ static inline void crypto_aead_clear_flags(struct crypto_aead *tfm, u32 flags) static inline int crypto_aead_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen) { - return crypto_aead_crt(tfm)->setkey(tfm, key, keylen); + struct aead_tfm *crt = crypto_aead_crt(tfm); + + return crt->setkey(crt->base, key, keylen); } +int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize); + static inline struct crypto_aead *crypto_aead_reqtfm(struct aead_request *req) { return __crypto_aead_cast(req->base.tfm); @@ -775,7 +806,7 @@ static inline unsigned int crypto_aead_reqsize(struct crypto_aead *tfm) static inline void aead_request_set_tfm(struct aead_request *req, struct crypto_aead *tfm) { - req->base.tfm = crypto_aead_tfm(tfm); + req->base.tfm = crypto_aead_tfm(crypto_aead_crt(tfm)->base); } static inline struct aead_request *aead_request_alloc(struct crypto_aead *tfm, @@ -841,9 +872,9 @@ static inline struct crypto_blkcipher *crypto_blkcipher_cast( static inline struct crypto_blkcipher *crypto_alloc_blkcipher( const char *alg_name, u32 type, u32 mask) { - type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); + type &= ~CRYPTO_ALG_TYPE_MASK; type |= CRYPTO_ALG_TYPE_BLKCIPHER; - mask |= CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC; + mask |= CRYPTO_ALG_TYPE_MASK; return __crypto_blkcipher_cast(crypto_alloc_base(alg_name, type, mask)); } @@ -861,9 +892,9 @@ static inline void crypto_free_blkcipher(struct crypto_blkcipher *tfm) static inline int crypto_has_blkcipher(const char *alg_name, u32 type, u32 mask) { - type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); + type &= ~CRYPTO_ALG_TYPE_MASK; type |= CRYPTO_ALG_TYPE_BLKCIPHER; - mask |= CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC; + mask |= CRYPTO_ALG_TYPE_MASK; return crypto_has_alg(alg_name, type, mask); } @@ -1081,6 +1112,7 @@ static inline struct crypto_hash *crypto_alloc_hash(const char *alg_name, u32 type, u32 mask) { type &= ~CRYPTO_ALG_TYPE_MASK; + mask &= ~CRYPTO_ALG_TYPE_MASK; type |= CRYPTO_ALG_TYPE_HASH; mask |= CRYPTO_ALG_TYPE_HASH_MASK; @@ -1100,6 +1132,7 @@ static inline void crypto_free_hash(struct crypto_hash *tfm) static inline int crypto_has_hash(const char *alg_name, u32 type, u32 mask) { type &= ~CRYPTO_ALG_TYPE_MASK; + mask &= ~CRYPTO_ALG_TYPE_MASK; type |= CRYPTO_ALG_TYPE_HASH; mask |= CRYPTO_ALG_TYPE_HASH_MASK; diff --git a/include/linux/device.h b/include/linux/device.h index 2e15822fe409..1880208964d6 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 a3b6035b6c86..55c9a6952f44 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 b3ec4a496d64..21398a5d688d 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 a47b8025d399..1dbea0ac5693 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/hw_random.h b/include/linux/hw_random.h index 21ea7610e177..85d11916e9ea 100644 --- a/include/linux/hw_random.h +++ b/include/linux/hw_random.h @@ -33,7 +33,7 @@ struct hwrng { const char *name; int (*init)(struct hwrng *rng); void (*cleanup)(struct hwrng *rng); - int (*data_present)(struct hwrng *rng); + int (*data_present)(struct hwrng *rng, int wait); int (*data_read)(struct hwrng *rng, u32 *data); unsigned long priv; diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 4a0d27f475d7..caa3f411f15d 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 6fee3539893f..5d185635786e 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 2cbc0b87e329..c97bdb7eb957 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 ab4cb6ecd47c..8f67e8f2a3cc 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 5ea4f05683f6..04b4d7330e6d 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 e80804316cdb..3261681c82a4 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 cc14656f8682..d6eacda765ca 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 e285746588d6..f752e73bf977 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 6b3a31805c72..2096b76d0cee 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 44c28e94df50..973386d439da 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 11f39606e7d9..cfbd38fe2998 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 b9d11a899b88..f5becd2a12f6 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 4efa1e5385e3..2ae5b8462399 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 @@ fail: * 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 65daa5373ca6..e53bc30e9ba5 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 c2e3e2e98801..dcb8a2cbf75e 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 7686417ee00e..b4da9505f4d2 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 05b64790fe83..b138b431e271 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 f71c9504a5c5..efc08360e627 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 195dc4611764..2093c3a9a994 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 e3055ba69159..092e4c620af9 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 c8a9d13874df..8d6125ad2cf0 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 e5e466b27598..ab46ae8c062b 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 8320a87f3e5a..ab4fd706993b 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 3590f022a609..1d63ead1815e 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 @@ out: } /** - * 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 @@ out: } /** - * 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 5886147252d0..5a402e2982af 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 @@ exit: 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 a6dc3ec328e0..9ecd6e865610 100644 --- a/lib/kref.c +++ b/lib/kref.c @@ -15,13 +15,23 @@ #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/slab.c b/mm/slab.c index b03b2e46b806..ff31261fd24f 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -304,11 +304,11 @@ struct kmem_list3 { /* * Need this for bootstrapping a per node allocator. */ -#define NUM_INIT_LISTS (2 * MAX_NUMNODES + 1) +#define NUM_INIT_LISTS (3 * MAX_NUMNODES) struct kmem_list3 __initdata initkmem_list3[NUM_INIT_LISTS]; #define CACHE_CACHE 0 -#define SIZE_AC 1 -#define SIZE_L3 (1 + MAX_NUMNODES) +#define SIZE_AC MAX_NUMNODES +#define SIZE_L3 (2 * MAX_NUMNODES) static int drain_freelist(struct kmem_cache *cache, struct kmem_list3 *l3, int tofree); @@ -1410,6 +1410,22 @@ static void init_list(struct kmem_cache *cachep, struct kmem_list3 *list, } /* + * For setting up all the kmem_list3s for cache whose buffer_size is same as + * size of kmem_list3. + */ +static void __init set_up_list3s(struct kmem_cache *cachep, int index) +{ + int node; + + for_each_online_node(node) { + cachep->nodelists[node] = &initkmem_list3[index + node]; + cachep->nodelists[node]->next_reap = jiffies + + REAPTIMEOUT_LIST3 + + ((unsigned long)cachep) % REAPTIMEOUT_LIST3; + } +} + +/* * Initialisation. Called after the page allocator have been initialised and * before smp_init(). */ @@ -1432,6 +1448,7 @@ void __init kmem_cache_init(void) if (i < MAX_NUMNODES) cache_cache.nodelists[i] = NULL; } + set_up_list3s(&cache_cache, CACHE_CACHE); /* * Fragmentation resistance on low memory - only use bigger @@ -1587,10 +1604,9 @@ void __init kmem_cache_init(void) { int nid; - /* Replace the static kmem_list3 structures for the boot cpu */ - init_list(&cache_cache, &initkmem_list3[CACHE_CACHE], node); - for_each_online_node(nid) { + init_list(&cache_cache, &initkmem_list3[CACHE_CACHE], nid); + init_list(malloc_sizes[INDEX_AC].cs_cachep, &initkmem_list3[SIZE_AC + nid], nid); @@ -1960,22 +1976,6 @@ static void slab_destroy(struct kmem_cache *cachep, struct slab *slabp) } } -/* - * For setting up all the kmem_list3s for cache whose buffer_size is same as - * size of kmem_list3. - */ -static void __init set_up_list3s(struct kmem_cache *cachep, int index) -{ - int node; - - for_each_online_node(node) { - cachep->nodelists[node] = &initkmem_list3[index + node]; - cachep->nodelists[node]->next_reap = jiffies + - REAPTIMEOUT_LIST3 + - ((unsigned long)cachep) % REAPTIMEOUT_LIST3; - } -} - static void __kmem_cache_destroy(struct kmem_cache *cachep) { int i; @@ -2099,7 +2099,7 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep) g_cpucache_up = PARTIAL_L3; } else { int node; - for_each_node_state(node, N_NORMAL_MEMORY) { + for_each_online_node(node) { cachep->nodelists[node] = kmalloc_node(sizeof(struct kmem_list3), GFP_KERNEL, node); diff --git a/mm/slub.c b/mm/slub.c index 474945ecd89d..5cc4b7dddb50 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 935784f736b3..298e0f463c56 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 @@ err2: 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 f666f7b28ff5..c11b554fd109 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 3312e8f2abe4..9cf0538d1717 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 79db51fcb476..02b2d50cce4d 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 57bb2236952c..74d97cc24787 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 5a4f0b6bcbed..8652d0f268ad 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 000000000000..4a194203c982 --- /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 000000000000..08d0d3ff3263 --- /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 000000000000..b0a1b4fe6584 --- /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 b28a8acae34d..acc6cf0d7900 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; } |