diff options
author | Vyacheslav Cherkashin <v.cherkashin@samsung.com> | 2015-04-27 15:22:12 +0300 |
---|---|---|
committer | Vyacheslav Cherkashin <v.cherkashin@samsung.com> | 2015-04-27 15:24:02 +0300 |
commit | 483630ae22b25b202c69d868592daf059f45ad10 (patch) | |
tree | c54643747d0921633ff3e3d8158dffeed18c2d05 | |
parent | d4e9632f5edd1601c0262193e558494abed80055 (diff) | |
parent | 823167ff5296299a977b4378cca82759b51580a4 (diff) | |
download | swap-modules-483630ae22b25b202c69d868592daf059f45ad10.tar.gz swap-modules-483630ae22b25b202c69d868592daf059f45ad10.tar.bz2 swap-modules-483630ae22b25b202c69d868592daf059f45ad10.zip |
Merge branch 'tizen_2.4' into 'tizen_2.4_dev'
Change-Id: I1133d65cd7fe8b74e084b4ea9e0bdc8fb470659d
Signed-off-by: Vyacheslav Cherkashin <v.cherkashin@samsung.com>
42 files changed, 1291 insertions, 400 deletions
@@ -1,6 +1,7 @@ EXTRA_CFLAGS := $(extra_cflags) -obj-m := buffer/ \ +obj-m := master/ \ + buffer/ \ ksyms/ \ driver/ \ writer/ \ diff --git a/LICENSE.GPL-2.0 b/LICENSE.GPL-2.0 new file mode 100755 index 00000000..d159169d --- /dev/null +++ b/LICENSE.GPL-2.0 @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/driver/Kbuild b/driver/Kbuild index bfee0652..b3e30301 100644 --- a/driver/Kbuild +++ b/driver/Kbuild @@ -4,8 +4,7 @@ KBUILD_EXTRA_SYMBOLS = $(src)/../buffer/Module.symvers obj-m := swap_driver.o swap_driver-y := swap_driver_module.o \ device_driver.o \ - driver_to_buffer.o \ - swap_debugfs.o + driver_to_buffer.o ifeq ($(CONFIG_CONNECTOR),y) swap_driver-y += us_interaction.o diff --git a/driver/device_driver.c b/driver/device_driver.c index bd015195..b4c56e49 100644 --- a/driver/device_driver.c +++ b/driver/device_driver.c @@ -43,6 +43,7 @@ #include <asm/uaccess.h> #include <ksyms/ksyms.h> +#include <master/swap_initializer.h> #include "device_driver.h" #include "swap_driver_errors.h" @@ -60,8 +61,6 @@ #define MAXIMUM_SUBBUFFER_SIZE (64 * 1024) /* swap_device driver routines */ -static int swap_device_open(struct inode *inode, struct file *filp); -static int swap_device_release(struct inode *inode, struct file *file); static ssize_t swap_device_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos); static long swap_device_ioctl(struct file *filp, unsigned int cmd, @@ -77,8 +76,8 @@ static ssize_t swap_device_splice_read(struct file *filp, loff_t *ppos, const struct file_operations swap_device_fops = { .owner = THIS_MODULE, .read = swap_device_read, - .open = swap_device_open, - .release = swap_device_release, + .open = swap_init_simple_open, + .release = swap_init_simple_release, .unlocked_ioctl = swap_device_ioctl, .splice_read = swap_device_splice_read, }; @@ -262,18 +261,6 @@ void swap_device_exit(void) unregister_chrdev_region(swap_device_no, 1); } -static int swap_device_open(struct inode *inode, struct file *filp) -{ - // TODO MOD_INC_USE_COUNT - return 0; -} - -static int swap_device_release(struct inode *inode, struct file *filp) -{ - // TODO MOD_DEC_USE_COUNT - return 0; -} - static ssize_t swap_device_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { diff --git a/driver/swap_debugfs.c b/driver/swap_debugfs.c deleted file mode 100644 index 976ed79c..00000000 --- a/driver/swap_debugfs.c +++ /dev/null @@ -1,73 +0,0 @@ -/** - * driver/swap_debugfs.c - * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com> - * - * @section 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. - * - * @section COPYRIGHT - * - * Copyright (C) Samsung Electronics, 2013 - * - * @section DESCRIPTION - * - * Initializes root debugfs for all SWAP modules - */ - - -#include <linux/module.h> -#include <linux/debugfs.h> - - -static struct dentry *swap_dir = NULL; - -/** - * @brief Get debugfs dir. - * - * @return Pointer to dentry stuct. - */ -struct dentry *get_swap_debugfs_dir(void) -{ - return swap_dir; -} -EXPORT_SYMBOL_GPL(get_swap_debugfs_dir); - -/** - * @brief Initializes SWAP debugfs. - * - * @return 0 on success, negative error code on error. - */ -int swap_debugfs_init(void) -{ - swap_dir = debugfs_create_dir("swap", NULL); - if (swap_dir == NULL) - return -ENOMEM; - - return 0; -} - -/** - * @brief Deinitializes SWAP debugfs and recursively removes all its files. - * - * @return Void. - */ -void swap_debugfs_exit(void) -{ - struct dentry *dir = swap_dir; - - swap_dir = NULL; - debugfs_remove_recursive(dir); -} diff --git a/driver/swap_driver_module.c b/driver/swap_driver_module.c index 08fb151a..48c70163 100644 --- a/driver/swap_driver_module.c +++ b/driver/swap_driver_module.c @@ -28,20 +28,15 @@ */ #include <linux/module.h> - +#include <master/swap_initializer.h> #include "driver_defs.h" #include "device_driver.h" -#include "swap_debugfs.h" #include "us_interaction.h" -static int __init swap_driver_init(void) +static int fs_init(void) { int ret; - ret = swap_debugfs_init(); - if (ret) - return ret; - ret = swap_device_init(); if (ret) goto dev_init_fail; @@ -55,22 +50,19 @@ static int __init swap_driver_init(void) return 0; dev_init_fail: - swap_debugfs_exit(); swap_device_exit(); return ret; } -static void __exit swap_driver_exit(void) +static void fs_uninit(void) { us_interaction_destroy(); swap_device_exit(); - swap_debugfs_exit(); print_msg("Driver module uninitialized\n"); } -module_init(swap_driver_init); -module_exit(swap_driver_exit); +SWAP_LIGHT_INIT_MODULE(NULL, NULL, NULL, fs_init, fs_uninit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SWAP device driver"); diff --git a/energy/debugfs_energy.c b/energy/debugfs_energy.c index bf72a66b..3d3da06e 100644 --- a/energy/debugfs_energy.c +++ b/energy/debugfs_energy.c @@ -27,8 +27,9 @@ #include <linux/module.h> #include <linux/debugfs.h> #include <linux/math64.h> -#include <driver/swap_debugfs.h> +#include <master/swap_debugfs.h> #include "energy.h" +#include "debugfs_energy.h" #include "rational_debugfs.h" #include "lcd/lcd_debugfs.h" @@ -131,7 +132,7 @@ static int get_func_u64(void *data, u64 *val) return 0; } -DEFINE_SIMPLE_ATTRIBUTE(fops_get_u64, get_func_u64, NULL, "%llu\n"); +SWAP_DEFINE_SIMPLE_ATTRIBUTE(fops_get_u64, get_func_u64, NULL, "%llu\n"); struct param_data { @@ -259,7 +260,7 @@ int init_debugfs_energy(void) int i; struct dentry *swap_dir, *dentry; - swap_dir = get_swap_debugfs_dir(); + swap_dir = swap_debugfs_getdir(); if (swap_dir == NULL) return -ENOENT; diff --git a/energy/debugfs_energy.h b/energy/debugfs_energy.h index f8ee51cb..52cc5af5 100644 --- a/energy/debugfs_energy.h +++ b/energy/debugfs_energy.h @@ -28,9 +28,47 @@ */ +#include <linux/fs.h> +#include <master/swap_initializer.h> + + struct dentry; +/* based on define DEFINE_SIMPLE_ATTRIBUTE */ +#define SWAP_DEFINE_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt) \ +static int __fops ## _open(struct inode *inode, struct file *file) \ +{ \ + int ret; \ + \ + ret = swap_init_simple_open(inode, file); \ + if (ret) \ + return ret; \ + \ + __simple_attr_check_format(__fmt, 0ull); \ + ret = simple_attr_open(inode, file, __get, __set, __fmt); \ + if (ret) \ + swap_init_simple_release(inode, file); \ + \ + return ret; \ +} \ +static int __fops ## _release(struct inode *inode, struct file *file) \ +{ \ + simple_attr_release(inode, file); \ + swap_init_simple_release(inode, file); \ + \ + return 0; \ +} \ +static const struct file_operations __fops = { \ + .owner = THIS_MODULE, \ + .open = __fops ## _open, \ + .release = __fops ## _release, \ + .read = simple_attr_read, \ + .write = simple_attr_write, \ + .llseek = generic_file_llseek, \ +} + + int init_debugfs_energy(void); void exit_debugfs_energy(void); diff --git a/energy/energy.c b/energy/energy.c index 9dbf9fd7..465bb1a7 100644 --- a/energy/energy.c +++ b/energy/energy.c @@ -640,6 +640,31 @@ unlock: } EXPORT_SYMBOL_GPL(unset_energy); +int energy_once(void) +{ + const char *sym; + + sym = "__switch_to"; + switch_to_krp.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym); + if (switch_to_krp.kp.addr == NULL) + goto not_found; + + sym = "sys_read"; + sys_read_krp.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym); + if (sys_read_krp.kp.addr == NULL) + goto not_found; + + sym = "sys_write"; + sys_write_krp.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym); + if (sys_write_krp.kp.addr == NULL) + goto not_found; + + return 0; + +not_found: + printk("ERROR: symbol '%s' not found\n", sym); + return -ESRCH; +} /** * @brief Initialization energy @@ -649,28 +674,6 @@ EXPORT_SYMBOL_GPL(unset_energy); int energy_init(void) { int ret; - unsigned long addr; - - addr = swap_ksyms("__switch_to"); - if (addr == 0) { - printk("Cannot find address for __switch_to function!\n"); - return -EINVAL; - } - switch_to_krp.kp.addr = (kprobe_opcode_t *)addr; - - addr = swap_ksyms("sys_read"); - if (addr == 0) { - printk("Cannot find address for sys_read function!\n"); - return -EINVAL; - } - sys_read_krp.kp.addr = (kprobe_opcode_t *)addr; - - addr = swap_ksyms("sys_write"); - if (addr == 0) { - printk("Cannot find address for sys_write function!\n"); - return -EINVAL; - } - sys_write_krp.kp.addr = (kprobe_opcode_t *)addr; ret = init_feature(); if (ret) { diff --git a/energy/energy.h b/energy/energy.h index 408a0f8e..9626d1d4 100644 --- a/energy/energy.h +++ b/energy/energy.h @@ -43,6 +43,7 @@ enum parameter_energy { }; +int energy_once(void); int energy_init(void); void energy_uninit(void); diff --git a/energy/energy_module.c b/energy/energy_module.c index 5196901c..b4ac328f 100644 --- a/energy/energy_module.c +++ b/energy/energy_module.c @@ -24,36 +24,12 @@ #include <linux/module.h> +#include <master/swap_initializer.h> #include "energy.h" #include "debugfs_energy.h" -static int __init swap_energy_init(void) -{ - int ret; - - ret = init_debugfs_energy(); - if (ret) { - printk("Cannot init debugfs for energy\n"); - return ret; - } - - ret = energy_init(); - if (ret) { - printk("Cannot init energy\n"); - exit_debugfs_energy(); - } - - return ret; -} - -static void __exit swap_energy_exit(void) -{ - energy_uninit(); - exit_debugfs_energy(); -} - -module_init(swap_energy_init); -module_exit(swap_energy_exit); +SWAP_LIGHT_INIT_MODULE(energy_once, energy_init, energy_uninit, + init_debugfs_energy, exit_debugfs_energy); MODULE_LICENSE("GPL"); diff --git a/energy/lcd/lcd_debugfs.c b/energy/lcd/lcd_debugfs.c index 841d4ce8..ef514e0a 100644 --- a/energy/lcd/lcd_debugfs.c +++ b/energy/lcd/lcd_debugfs.c @@ -27,6 +27,7 @@ #include <linux/module.h> #include <linux/slab.h> #include <energy/lcd/lcd_base.h> +#include <energy/debugfs_energy.h> #include <energy/rational_debugfs.h> @@ -64,7 +65,7 @@ static int get_system(void *data, u64 *val) return 0; } -DEFINE_SIMPLE_ATTRIBUTE(fops_get_system, get_system, NULL, "%llu\n"); +SWAP_DEFINE_SIMPLE_ATTRIBUTE(fops_get_system, get_system, NULL, "%llu\n"); static struct dentry *lcd_dir = NULL; diff --git a/energy/rational_debugfs.c b/energy/rational_debugfs.c index 32a3f1b2..6ee9c1bb 100644 --- a/energy/rational_debugfs.c +++ b/energy/rational_debugfs.c @@ -26,6 +26,7 @@ #include <linux/dcache.h> #include <linux/debugfs.h> #include <linux/module.h> +#include "debugfs_energy.h" #include "rational_debugfs.h" @@ -44,7 +45,7 @@ static int denom_get(void *data, u64 *val) return 0; } -DEFINE_SIMPLE_ATTRIBUTE(fops_denom, denom_get, denom_set, "%llu\n"); +SWAP_DEFINE_SIMPLE_ATTRIBUTE(fops_denom, denom_get, denom_set, "%llu\n"); /** * @brief Create file in debugfs for rational struct diff --git a/kprobe/arch/arm/swap-asm/memory_rwx.c b/kprobe/arch/arm/swap-asm/memory_rwx.c index bb751a66..e74f095e 100644 --- a/kprobe/arch/arm/swap-asm/memory_rwx.c +++ b/kprobe/arch/arm/swap-asm/memory_rwx.c @@ -94,7 +94,7 @@ void mem_rwx_write_u32(unsigned long addr, unsigned long val) } } -int mem_rwx_init(void) +int mem_rwx_once(void) { const char *sym; diff --git a/kprobe/arch/arm/swap-asm/memory_rwx.h b/kprobe/arch/arm/swap-asm/memory_rwx.h index 97879bba..f5339656 100644 --- a/kprobe/arch/arm/swap-asm/memory_rwx.h +++ b/kprobe/arch/arm/swap-asm/memory_rwx.h @@ -29,8 +29,7 @@ #define _MEMORY_RWX_H -int mem_rwx_init(void); -void mem_rwx_exit(void) {}; +int mem_rwx_once(void); void mem_rwx_write_u32(unsigned long addr, unsigned long val); diff --git a/kprobe/arch/arm/swap-asm/swap_kprobes.c b/kprobe/arch/arm/swap-asm/swap_kprobes.c index e0b989b1..e264e5ae 100644 --- a/kprobe/arch/arm/swap-asm/swap_kprobes.c +++ b/kprobe/arch/arm/swap-asm/swap_kprobes.c @@ -467,7 +467,7 @@ int kprobe_trap_handler(struct pt_regs *regs, unsigned int instr) local_irq_save(flags); preempt_disable(); ret = kprobe_handler(regs); - preempt_enable_no_resched(); + swap_preempt_enable_no_resched(); local_irq_restore(flags); #ifdef SUPRESS_BUG_MESSAGES @@ -862,33 +862,46 @@ static struct undef_hook undef_ho_k = { }; /** - * @brief Initializes kprobes module for ARM arch. + * @brief Arch-dependend module deps initialization stub. * - * @return 0 on success, error code on error. + * @return 0. */ -int swap_arch_init_kprobes(void) +int arch_init_module_deps(void) { + const char *sym; +#ifdef CONFIG_STRICT_MEMORY_RWX int ret; -#ifdef CONFIG_STRICT_MEMORY_RWX - ret = mem_rwx_init(); + ret = mem_rwx_once(); if (ret) return ret; #endif /* CONFIG_STRICT_MEMORY_RWX */ - // Register hooks (kprobe_handler) - __swap_register_undef_hook = (void *)swap_ksyms("register_undef_hook"); - if (__swap_register_undef_hook == NULL) { - printk("no register_undef_hook symbol found!\n"); - return -1; - } + sym = "register_undef_hook"; + __swap_register_undef_hook = (void *)swap_ksyms(sym); + if (__swap_register_undef_hook == NULL) + goto not_found; + + sym = "unregister_undef_hook"; + __swap_unregister_undef_hook = (void *)swap_ksyms(sym); + if (__swap_unregister_undef_hook == NULL) + goto not_found; + + return 0; + +not_found: + printk("ERROR: symbol '%s' not found\n", sym); + return -ESRCH; +} - // Unregister hooks (kprobe_handler) - __swap_unregister_undef_hook = (void *)swap_ksyms("unregister_undef_hook"); - if (__swap_unregister_undef_hook == NULL) { - printk("no unregister_undef_hook symbol found!\n"); - return -1; - } +/** + * @brief Initializes kprobes module for ARM arch. + * + * @return 0 on success, error code on error. + */ +int swap_arch_init_kprobes(void) +{ + int ret; swap_register_undef_hook(&undef_ho_k); @@ -910,10 +923,6 @@ void swap_arch_exit_kprobes(void) { kjump_exit(); swap_unregister_undef_hook(&undef_ho_k); - -#ifdef CONFIG_STRICT_MEMORY_RWX - mem_rwx_exit(); -#endif /* CONFIG_STRICT_MEMORY_RWX */ } /* export symbol for trampoline_arm.h */ diff --git a/kprobe/arch/arm/swap-asm/swap_kprobes.h b/kprobe/arch/arm/swap-asm/swap_kprobes.h index f7c53cae..2376324d 100644 --- a/kprobe/arch/arm/swap-asm/swap_kprobes.h +++ b/kprobe/arch/arm/swap-asm/swap_kprobes.h @@ -601,15 +601,7 @@ struct undef_hook; void swap_register_undef_hook(struct undef_hook *hook); void swap_unregister_undef_hook(struct undef_hook *hook); -/** - * @brief Arch-dependend module deps initialization stub. - * - * @return 0. - */ -static inline int arch_init_module_deps(void) -{ - return 0; -} +int arch_init_module_deps(void); int arch_make_trampoline_arm(unsigned long addr, unsigned long insn, unsigned long *tramp); diff --git a/kprobe/arch/x86/swap-asm/swap_kprobes.c b/kprobe/arch/x86/swap-asm/swap_kprobes.c index 0e671f96..e0588403 100644 --- a/kprobe/arch/x86/swap-asm/swap_kprobes.c +++ b/kprobe/arch/x86/swap-asm/swap_kprobes.c @@ -330,7 +330,7 @@ static int setup_singlestep(struct kprobe *p, struct pt_regs *regs, /* Boost up -- we can execute copied instructions directly */ swap_reset_current_kprobe(); regs->ip = (unsigned long)p->ainsn.insn; - preempt_enable_no_resched(); + swap_preempt_enable_no_resched(); return 1; } @@ -437,7 +437,7 @@ ss_probe: return 1; no_kprobe: - preempt_enable_no_resched (); + swap_preempt_enable_no_resched(); return ret; } @@ -667,7 +667,7 @@ static int post_kprobe_handler (struct pt_regs *regs) } swap_reset_current_kprobe(); out: - preempt_enable_no_resched (); + swap_preempt_enable_no_resched(); /* * if somebody else is singlestepping across a probe point, eflags @@ -702,7 +702,7 @@ static int kprobe_fault_handler(struct pt_regs *regs, int trapnr) restore_previous_kprobe (kcb); else swap_reset_current_kprobe(); - preempt_enable_no_resched (); + swap_preempt_enable_no_resched(); break; case KPROBE_HIT_ACTIVE: case KPROBE_HIT_SSDONE: @@ -823,7 +823,7 @@ int swap_longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) } *regs = kcb->jprobe_saved_regs; memcpy ((kprobe_opcode_t *) stack_addr, kcb->jprobes_stack, MIN_STACK_SIZE (stack_addr)); - preempt_enable_no_resched (); + swap_preempt_enable_no_resched(); return 1; } @@ -945,7 +945,7 @@ int set_kjump_cb(struct pt_regs *regs, jumper_cb_t cb, void *data, size_t size) regs->ip = (unsigned long)&kjump_trampoline; swap_reset_current_kprobe(); - preempt_enable_no_resched(); + swap_preempt_enable_no_resched(); return 1; } diff --git a/kprobe/swap_kprobes.c b/kprobe/swap_kprobes.c index 26297106..32f357f4 100644 --- a/kprobe/swap_kprobes.c +++ b/kprobe/swap_kprobes.c @@ -42,6 +42,7 @@ #include <linux/pagemap.h> #include <ksyms/ksyms.h> +#include <master/swap_initializer.h> #include <swap-asm/swap_kprobes.h> #include "swap_slots.h" @@ -781,7 +782,7 @@ int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) } spin_unlock_irqrestore(&kretprobe_lock, flags); - preempt_enable_no_resched(); + swap_preempt_enable_no_resched(); /* * By returning a non-zero value, we are telling @@ -1097,48 +1098,55 @@ static int init_module_deps(void) return arch_init_module_deps(); } -static int __init init_kprobes(void) +static int once(void) { - int i, err = 0; + int i, ret; + const char *sym; - module_alloc = (void *)swap_ksyms("module_alloc"); - if (!module_alloc) { - printk("module_alloc is not found! Oops.\n"); - return -1; - } - module_free = (void *)swap_ksyms("module_free"); - if (!module_alloc) { - printk("module_free is not found! Oops.\n"); - return -1; - } + sym = "module_alloc"; + module_alloc = (void *)swap_ksyms(sym); + if (module_alloc == NULL) + goto not_found; - init_sm(); + sym = "module_free"; + module_free = (void *)swap_ksyms(sym); + if (module_alloc == NULL) + goto not_found; + + ret = init_module_deps(); + if (ret) + return ret; - /* FIXME allocate the probe table, currently defined statically */ - /* initialize all list heads */ + /* + * FIXME allocate the probe table, currently defined statically + * initialize all list heads + */ for (i = 0; i < KPROBE_TABLE_SIZE; ++i) { INIT_HLIST_HEAD(&kprobe_table[i]); INIT_HLIST_HEAD(&kretprobe_inst_table[i]); } - atomic_set(&kprobe_count, 0); - err = init_module_deps(); - if (err) { - return err; - } + return 0; + +not_found: + printk("ERROR: symbol '%s' not found\n", sym); + return -ESRCH; +} - err = swap_arch_init_kprobes(); +static int init_kprobes(void) +{ + init_sm(); + atomic_set(&kprobe_count, 0); - return err; + return swap_arch_init_kprobes(); } -static void __exit exit_kprobes(void) +static void exit_kprobes(void) { swap_arch_exit_kprobes(); exit_sm(); } -module_init(init_kprobes); -module_exit(exit_kprobes); +SWAP_LIGHT_INIT_MODULE(once, init_kprobes, exit_kprobes, NULL, NULL); MODULE_LICENSE("GPL"); diff --git a/kprobe/swap_kprobes_deps.h b/kprobe/swap_kprobes_deps.h index 70824def..6d531b0f 100644 --- a/kprobe/swap_kprobes_deps.h +++ b/kprobe/swap_kprobes_deps.h @@ -55,6 +55,30 @@ #define synchronize_sched synchronize_kernel #endif + +/* + * TODO: possibly unnided + * check and remove swap_preempt_enable_no_resched() call + */ +#if (defined(MODULE) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))) + +#ifdef CONFIG_PREEMPT_COUNT +#define swap_preempt_enable_no_resched() \ +do { \ + barrier(); \ + preempt_count_dec(); \ +} while (0) +#else /* !CONFIG_PREEMPT_COUNT */ +#define swap_preempt_enable_no_resched() barrier() +#endif /* CONFIG_PREEMPT_COUNT */ + +#else /* !(defined(MODULE) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */ + +#define swap_preempt_enable_no_resched() preempt_enable_no_resched() + +#endif /* !(defined(MODULE) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */ + + //--------------------- Declaration of module dependencies ------------------------// #define DECLARE_MOD_FUNC_DEP(name, ret, ...) ret(*__ref_##name)(__VA_ARGS__) diff --git a/ks_features/ks_features.c b/ks_features/ks_features.c index 303af2ab..97ace335 100644 --- a/ks_features/ks_features.c +++ b/ks_features/ks_features.c @@ -34,6 +34,7 @@ #include <asm/errno.h> #include <ksyms/ksyms.h> #include <kprobe/swap_kprobes.h> +#include <master/swap_initializer.h> #include <writer/swap_writer_module.h> #include <writer/event_filter.h> #include "ks_features.h" @@ -538,7 +539,8 @@ static void uninit_syscall_features(void) } } -static int __init init_ks_feature(void) + +static int once(void) { int ret; @@ -547,20 +549,17 @@ static int __init init_ks_feature(void) return ret; ret = init_syscall_features(); - if (ret) - exit_switch_context(); return ret; } -static void __exit exit_ks_feature(void) +static void core_uninit(void) { uninit_syscall_features(); exit_switch_context(); } -module_init(init_ks_feature); -module_exit(exit_ks_feature); +SWAP_LIGHT_INIT_MODULE(once, NULL, core_uninit, NULL, NULL); MODULE_LICENSE("GPL"); diff --git a/master/Kbuild b/master/Kbuild new file mode 100644 index 00000000..83733a74 --- /dev/null +++ b/master/Kbuild @@ -0,0 +1,6 @@ +EXTRA_CFLAGS := $(extra_cflags) + +obj-m := swap_master.o +swap_master-y := master_module.o \ + swap_debugfs.o \ + swap_initializer.o diff --git a/master/master_module.c b/master/master_module.c new file mode 100644 index 00000000..e3b75530 --- /dev/null +++ b/master/master_module.c @@ -0,0 +1,41 @@ +/* + * 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. + * + * Copyright (C) Samsung Electronics, 2015 + * + * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com> + * + */ + + +#include <linux/module.h> +#include "swap_debugfs.h" +#include "swap_initializer.h" + + +static int __init master_init(void) +{ + return swap_debugfs_init(); +} + +static void __exit master_exit(void) +{ + swap_debugfs_uninit(); +} + +module_init(master_init); +module_exit(master_exit); + +MODULE_LICENSE("GPL"); diff --git a/master/swap_debugfs.c b/master/swap_debugfs.c new file mode 100644 index 00000000..d35f75e4 --- /dev/null +++ b/master/swap_debugfs.c @@ -0,0 +1,173 @@ +/* + * 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. + * + * Copyright (C) Samsung Electronics, 2015 + * + * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com> + * + */ + + +#include <linux/module.h> +#include <linux/debugfs.h> +#include <asm/uaccess.h> +#include "swap_initializer.h" + + +static int set_enable(int enable) +{ + int ret = 0, change, enable_current; + + enable_current = swap_init_stat_get(); + + change = ((!!enable_current) << 1) | (!!enable); + switch (change) { + case 0b01: /* init */ + ret = swap_init_init(); + break; + case 0b10: /* uninit */ + ret = swap_init_uninit(); + break; + default: + ret = -EINVAL; + break; + } + + swap_init_stat_put(); + + return ret; +} + +static ssize_t read_enable(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + char buf[3]; + int enable; + + enable = swap_init_stat_get(); + swap_init_stat_put(); + + if (enable) + buf[0] = '1'; + else + buf[0] = '0'; + buf[1] = '\n'; + buf[2] = '\0'; + + return simple_read_from_buffer(user_buf, count, ppos, buf, 2); +} + +static int do_write_enable(const char *buf, size_t size) +{ + if (size < 1) + return -EINVAL; + + switch (buf[0]) { + case '1': + return set_enable(1); + case '0': + return set_enable(0); + } + + return -EINVAL; +} + +static ssize_t write_enable(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + int ret; + char buf[32]; + size_t buf_size; + + buf_size = min(count, (sizeof(buf) - 1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + + ret = do_write_enable(buf, buf_size); + + return ret ? ret : count; +} + +static const struct file_operations fops_enable = { + .owner = THIS_MODULE, + .read = read_enable, + .write = write_enable, + .llseek = default_llseek, +}; + + +static struct dentry *swap_dir = NULL; + +/** + * @brief Get debugfs dir. + * + * @return Pointer to dentry stuct. + */ +struct dentry *swap_debugfs_getdir(void) +{ + return swap_dir; +} +EXPORT_SYMBOL_GPL(swap_debugfs_getdir); + +static int debugfs_dir_init(void) +{ + swap_dir = debugfs_create_dir("swap", NULL); + if (swap_dir == NULL) + return -ENOMEM; + + return 0; +} + +static void debugfs_dir_exit(void) +{ + struct dentry *dir = swap_dir; + + swap_dir = NULL; + debugfs_remove_recursive(dir); +} + +/** + * @brief Initializes SWAP debugfs. + * + * @return 0 on success, negative error code on error. + */ +int swap_debugfs_init(void) +{ + int ret; + struct dentry *dentry; + + ret = debugfs_dir_init(); + if (ret) + return ret; + + dentry = debugfs_create_file("enable", 0600, swap_dir, NULL, + &fops_enable); + if (dentry == NULL) { + debugfs_dir_exit(); + return -ENOMEM; + } + + return 0; +} + +/** + * @brief Deinitializes SWAP debugfs and recursively removes all its files. + * + * @return Void. + */ +void swap_debugfs_uninit(void) +{ + debugfs_dir_exit(); +} diff --git a/driver/swap_debugfs.h b/master/swap_debugfs.h index a1912a2b..0df8c3a7 100644 --- a/driver/swap_debugfs.h +++ b/master/swap_debugfs.h @@ -1,5 +1,4 @@ /** - * @file driver/swap_debugfs.h * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com> * * @section LICENSE @@ -20,22 +19,23 @@ * * @section COPYRIGHT * - * Copyright (C) Samsung Electronics, 2013 + * Copyright (C) Samsung Electronics, 2015 * * @section DESCRIPTION * * SWAP debugfs interface definition. */ +#ifndef _SWAP_DEBUGFS_H +#define _SWAP_DEBUGFS_H -#ifndef _SWAP_DEBUG_FS_H -#define _SWAP_DEBUG_FS_H struct dentry; +struct dentry *swap_debugfs_getdir(void); -struct dentry *get_swap_debugfs_dir(void); int swap_debugfs_init(void); -void swap_debugfs_exit(void); +void swap_debugfs_uninit(void); -#endif /* _SWAP_DEBUG_FS_H */ + +#endif /* _SWAP_DEBUGFS_H */ diff --git a/master/swap_initializer.c b/master/swap_initializer.c new file mode 100644 index 00000000..8b887fdb --- /dev/null +++ b/master/swap_initializer.c @@ -0,0 +1,352 @@ +/* + * 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. + * + * Copyright (C) Samsung Electronics, 2015 + * + * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com> + * + */ + + +#include <linux/slab.h> +#include <linux/list.h> +#include <linux/mutex.h> +#include <linux/types.h> +#include <linux/spinlock.h> +#include "swap_initializer.h" + + +enum init_level { + IL_CORE, + IL_FS +}; + +static swap_init_t sis_get_fn_init(struct swap_init_struct *init, + enum init_level level) +{ + switch (level) { + case IL_CORE: + return init->core_init; + case IL_FS: + return init->fs_init; + default: + return NULL; + } +} + +static swap_uninit_t sis_get_fn_uninit(struct swap_init_struct *init, + enum init_level level) +{ + switch (level) { + case IL_CORE: + return init->core_uninit; + case IL_FS: + return init->fs_uninit; + } + + return NULL; +} + +static void sis_set_flag(struct swap_init_struct *init, + enum init_level level, bool val) +{ + switch (level) { + case IL_CORE: + init->core_flag = val; + break; + case IL_FS: + init->fs_flag = val; + break; + } +} + +static bool sis_get_flag(struct swap_init_struct *init, enum init_level level) +{ + switch (level) { + case IL_CORE: + return init->core_flag; + case IL_FS: + return init->fs_flag; + } + + return false; +} + +static int sis_once(struct swap_init_struct *init) +{ + swap_init_t once; + + once = init->once; + if (!init->once_flag && once) { + int ret; + + ret = once(); + if (ret) + return ret; + + init->once_flag = true; + } + + return 0; +} + +static int sis_init_level(struct swap_init_struct *init, enum init_level level) +{ + int ret; + swap_init_t fn; + + if (sis_get_flag(init, level)) + return -EPERM; + + fn = sis_get_fn_init(init, level); + if (fn) { + ret = fn(); + if (ret) + return ret; + } + + sis_set_flag(init, level, true); + return 0; +} + +static void sis_uninit_level(struct swap_init_struct *init, + enum init_level level) +{ + if (sis_get_flag(init, level)) { + swap_uninit_t fn = sis_get_fn_uninit(init, level); + if (fn) + fn(); + sis_set_flag(init, level, false); + } +} + +static int sis_init(struct swap_init_struct *init) +{ + int ret; + + ret = sis_once(init); + if (ret) + return ret; + + ret = sis_init_level(init, IL_CORE); + if (ret) + return ret; + + ret = sis_init_level(init, IL_FS); + if (ret) + sis_uninit_level(init, IL_CORE); + + return ret; +} + +static void sis_uninit(struct swap_init_struct *init) +{ + sis_uninit_level(init, IL_FS); + sis_uninit_level(init, IL_CORE); +} + +static LIST_HEAD(init_list); +static DEFINE_MUTEX(inst_mutex); +static unsigned init_flag = 0; + +static int do_once(void) +{ + int ret; + struct swap_init_struct *init; + + list_for_each_entry(init, &init_list, list) { + ret = sis_once(init); + if (ret) + return ret; + } + + return 0; +} + +static void do_uninit_level(enum init_level level) +{ + struct swap_init_struct *init; + + list_for_each_entry(init, &init_list, list) + sis_uninit_level(init, level); +} + +static int do_init_level(enum init_level level) +{ + int ret; + struct swap_init_struct *init; + + list_for_each_entry(init, &init_list, list) { + ret = sis_init_level(init, level); + if (ret) { + do_uninit_level(level); + return ret; + } + } + + return 0; +} + +static int do_init(void) +{ + int ret; + + ret = do_once(); + if (ret) + return ret; + + ret = do_init_level(IL_CORE); + if (ret) + return ret; + + ret = do_init_level(IL_FS); + if (ret) + do_uninit_level(IL_CORE); + + init_flag = 1; + + return 0; +} + +static void do_uninit(void) +{ + do_uninit_level(IL_FS); + do_uninit_level(IL_CORE); + + init_flag = 0; +} + + +static atomic_t init_use = ATOMIC_INIT(0); + +enum init_stat_t { + IS_OFF, + IS_SWITCHING, + IS_ON, +}; + +static enum init_stat_t init_stat; +static DEFINE_SPINLOCK(init_stat_lock); + + +static bool swap_init_try_get(void) +{ + spin_lock(&init_stat_lock); + if (init_stat != IS_ON) { + spin_unlock(&init_stat_lock); + return false; + } + spin_unlock(&init_stat_lock); + + atomic_inc(&init_use); + + return true; +} + +static void swap_init_put(void) +{ + atomic_dec(&init_use); +} + +int swap_init_simple_open(struct inode *inode, struct file *file) +{ + if (swap_init_try_get() == false) + return -EBUSY; + + return 0; +} +EXPORT_SYMBOL_GPL(swap_init_simple_open); + +int swap_init_simple_release(struct inode *inode, struct file *file) +{ + swap_init_put(); + return 0; +} +EXPORT_SYMBOL_GPL(swap_init_simple_release); + +int swap_init_init(void) +{ + int ret; + + spin_lock(&init_stat_lock); + init_stat = IS_SWITCHING; + spin_unlock(&init_stat_lock); + + ret = do_init(); + + spin_lock(&init_stat_lock); + init_stat = ret ? IS_OFF : IS_ON; + spin_unlock(&init_stat_lock); + + return ret; +} + +int swap_init_uninit(void) +{ + spin_lock(&init_stat_lock); + init_stat = IS_SWITCHING; + if (atomic_read(&init_use)) { + init_stat = IS_ON; + spin_unlock(&init_stat_lock); + return -EBUSY; + } + spin_unlock(&init_stat_lock); + + do_uninit(); + + spin_lock(&init_stat_lock); + init_stat = IS_OFF; + spin_unlock(&init_stat_lock); + + return 0; +} + + +int swap_init_stat_get(void) +{ + mutex_lock(&inst_mutex); + + return init_flag; +} + +void swap_init_stat_put(void) +{ + mutex_unlock(&inst_mutex); +} + +int swap_init_register(struct swap_init_struct *init) +{ + int ret = 0; + + mutex_lock(&inst_mutex); + if (init_flag) + ret = sis_init(init); + + if (ret == 0) + list_add(&init->list, &init_list); + mutex_unlock(&inst_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(swap_init_register); + +void swap_init_unregister(struct swap_init_struct *init) +{ + mutex_lock(&inst_mutex); + list_del(&init->list); + sis_uninit(init); + mutex_unlock(&inst_mutex); +} +EXPORT_SYMBOL_GPL(swap_init_unregister); diff --git a/master/swap_initializer.h b/master/swap_initializer.h new file mode 100644 index 00000000..e0e6314f --- /dev/null +++ b/master/swap_initializer.h @@ -0,0 +1,100 @@ +/** + * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com> + * + * @section 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. + * + * @section COPYRIGHT + * + * Copyright (C) Samsung Electronics, 2015 + * + * @section DESCRIPTION + * + * SWAP event notification interface. + */ + +#ifndef _SWAP_INITIALIZER_H +#define _SWAP_INITIALIZER_H + + +#include <linux/list.h> +#include <linux/types.h> +#include <linux/module.h> + + +struct file; +struct inode; + + +typedef int (*swap_init_t)(void); +typedef void (*swap_uninit_t)(void); + + +struct swap_init_struct { + swap_init_t once; /* to call only on the first initialization */ + + swap_init_t core_init; + swap_uninit_t core_uninit; + + swap_init_t fs_init; + swap_uninit_t fs_uninit; + + /* private fields */ + struct list_head list; + unsigned once_flag:1; + unsigned core_flag:1; + unsigned fs_flag:1; +}; + + +int swap_init_simple_open(struct inode *inode, struct file *file); +int swap_init_simple_release(struct inode *inode, struct file *file); + +int swap_init_init(void); +int swap_init_uninit(void); + +int swap_init_stat_get(void); +void swap_init_stat_put(void); + +int swap_init_register(struct swap_init_struct *init); +void swap_init_unregister(struct swap_init_struct *init); + + +#define SWAP_LIGHT_INIT_MODULE(_once, _init, _uninit, _fs_init, _fs_uninit) \ + static struct swap_init_struct __init_struct = { \ + .once = _once, \ + .core_init = _init, \ + .core_uninit = _uninit, \ + .fs_init = _fs_init, \ + .fs_uninit = _fs_uninit, \ + .list = LIST_HEAD_INIT(__init_struct.list), \ + .once_flag = false, \ + .core_flag = false, \ + .fs_flag = false \ + }; \ + static int __init __init_mod(void) \ + { \ + return swap_init_register(&__init_struct); \ + } \ + static void __exit __exit_mod(void) \ + { \ + swap_init_unregister(&__init_struct); \ + } \ + module_init(__init_mod); \ + module_exit(__exit_mod) + + +#endif /* _SWAP_INITIALIZER_H */ diff --git a/packaging/swap-modules.spec b/packaging/swap-modules.spec index 5cbc90d9..b3dd375f 100755 --- a/packaging/swap-modules.spec +++ b/packaging/swap-modules.spec @@ -16,7 +16,7 @@ BuildRequires: kernel-devel %else %define build_arch i386 BuildRequires: emulator-kernel-devel -%define kernel_path /usr/src/linux-kernel-build-3.12.18 +%define kernel_path /usr/src/linux-kernel-build-3.14.25 %endif Provides: swap-modules %description @@ -30,6 +30,7 @@ Kernel modules for SWAP %install mkdir -p %{buildroot}/opt/swap/sdk +install -m 666 master/swap_master.ko -t %{buildroot}/opt/swap/sdk install -m 666 buffer/swap_buffer.ko -t %{buildroot}/opt/swap/sdk install -m 666 ksyms/swap_ksyms.ko -t %{buildroot}/opt/swap/sdk install -m 666 driver/swap_driver.ko -t %{buildroot}/opt/swap/sdk @@ -49,6 +50,7 @@ install -m 666 preload/swap_preload.ko -t %{buildroot}/opt/swap/sdk %files %defattr(-,root,root) +/opt/swap/sdk/swap_master.ko /opt/swap/sdk/swap_buffer.ko /opt/swap/sdk/swap_ksyms.ko /opt/swap/sdk/swap_driver.ko diff --git a/parser/features.c b/parser/features.c index fae53eac..085ce938 100644 --- a/parser/features.c +++ b/parser/features.c @@ -450,7 +450,7 @@ static u64 feature_mask = 0; * * @return 0. */ -int init_features(void) +int once_features(void) { int i; for (i = 0; i < SIZE_FEATURE_LIST; ++i) { @@ -464,15 +464,6 @@ int init_features(void) return 0; } -/** - * @brief Uninits features list. - * - * @return Void. - */ -void uninit_features(void) -{ -} - static int do_set_features(struct conf_data *conf) { int i, ret; diff --git a/parser/features.h b/parser/features.h index 765bc783..170771a2 100644 --- a/parser/features.h +++ b/parser/features.h @@ -33,8 +33,7 @@ struct conf_data; -int init_features(void); -void uninit_features(void); +int once_features(void); int set_features(struct conf_data *conf); diff --git a/parser/msg_cmd.c b/parser/msg_cmd.c index c1434143..e511207d 100644 --- a/parser/msg_cmd.c +++ b/parser/msg_cmd.c @@ -271,21 +271,7 @@ int get_wrt_launcher_port(void) * * @return Initialization results. */ -int init_cmd(void) +int once_cmd(void) { - int ret; - - ret = init_features(); - - return ret; -} - -/** - * @brief Uninitializes commands handling. - * - * @return Void. - */ -void uninit_cmd(void) -{ - uninit_features(); + return once_features(); } diff --git a/parser/msg_cmd.h b/parser/msg_cmd.h index e4449979..e0781699 100644 --- a/parser/msg_cmd.h +++ b/parser/msg_cmd.h @@ -32,8 +32,7 @@ struct msg_buf; -int init_cmd(void); -void uninit_cmd(void); +int once_cmd(void); int msg_keep_alive(struct msg_buf *mb); int msg_start(struct msg_buf *mb); diff --git a/parser/swap_msg_parser.c b/parser/swap_msg_parser.c index dca29999..af64bd13 100644 --- a/parser/swap_msg_parser.c +++ b/parser/swap_msg_parser.c @@ -41,6 +41,7 @@ #include <driver/driver_to_msg.h> #include <driver/swap_ioctl.h> +#include <master/swap_initializer.h> /** * @enum MSG_ID @@ -152,39 +153,30 @@ uninit: return ret; } -static void register_msg_handler(void) +static int reg_msg_handler(void) { set_msg_handler(msg_handler); + return 0; } -static void unregister_msg_handler(void) +static void unreg_msg_handler(void) { set_msg_handler(NULL); } -static int __init swap_parser_init(void) +static int once(void) { int ret; - ret = init_cpu_deps(); + ret = once_cmd(); if (ret) - goto out; - - register_msg_handler(); + return ret; - ret = init_cmd(); + ret = init_cpu_deps(); -out: return ret; } -static void __exit swap_parser_exit(void) -{ - uninit_cmd(); - unregister_msg_handler(); -} - -module_init(swap_parser_init); -module_exit(swap_parser_exit); +SWAP_LIGHT_INIT_MODULE(once, reg_msg_handler, unreg_msg_handler, NULL, NULL); MODULE_LICENSE("GPL"); diff --git a/preload/preload_debugfs.c b/preload/preload_debugfs.c index d9b4d188..8af94bbf 100644 --- a/preload/preload_debugfs.c +++ b/preload/preload_debugfs.c @@ -7,7 +7,7 @@ #include <linux/mutex.h> #include <linux/limits.h> #include <asm/uaccess.h> -#include <driver/swap_debugfs.h> +#include <master/swap_debugfs.h> #include "preload.h" #include "preload_debugfs.h" #include "preload_module.h" @@ -381,7 +381,7 @@ int preload_debugfs_init(void) goto fail; ret = -ENOENT; - swap_dentry = get_swap_debugfs_dir(); + swap_dentry = swap_debugfs_getdir(); if (!swap_dentry) goto fail; diff --git a/uprobe/arch/arm/swap-asm/swap_uprobes.c b/uprobe/arch/arm/swap-asm/swap_uprobes.c index 0a3786a4..cb6ae3d7 100644 --- a/uprobe/arch/arm/swap-asm/swap_uprobes.c +++ b/uprobe/arch/arm/swap-asm/swap_uprobes.c @@ -909,7 +909,7 @@ int uprobe_trap_handler(struct pt_regs *regs, unsigned int instr) preempt_disable(); ret = uprobe_handler(regs); - preempt_enable_no_resched(); + swap_preempt_enable_no_resched(); local_irq_restore(flags); return ret; diff --git a/uprobe/swap_uprobes.c b/uprobe/swap_uprobes.c index 08d33f2c..dff5be8f 100644 --- a/uprobe/swap_uprobes.c +++ b/uprobe/swap_uprobes.c @@ -35,6 +35,7 @@ #include <linux/mempolicy.h> #include <linux/module.h> +#include <master/swap_initializer.h> #include <kprobe/swap_slots.h> #include <kprobe/swap_kdebug.h> #include <kprobe/swap_kprobes_deps.h> @@ -997,21 +998,16 @@ void swap_ujprobe_return(void) } EXPORT_SYMBOL_GPL(swap_ujprobe_return); -static int __init init_uprobes(void) +static int once(void) { init_uprobe_table(); init_uprobes_insn_slots(); init_uretprobe_inst_table(); - return swap_arch_init_uprobes(); -} - -static void __exit exit_uprobes(void) -{ - swap_arch_exit_uprobes(); + return 0; } -module_init(init_uprobes); -module_exit(exit_uprobes); +SWAP_LIGHT_INIT_MODULE(once, swap_arch_init_uprobes, swap_arch_exit_uprobes, + NULL, NULL); MODULE_LICENSE ("GPL"); diff --git a/us_manager/debugfs_us_manager.c b/us_manager/debugfs_us_manager.c index c18f8374..09590c28 100644 --- a/us_manager/debugfs_us_manager.c +++ b/us_manager/debugfs_us_manager.c @@ -1,7 +1,8 @@ #include <linux/debugfs.h> #include <linux/module.h> -#include <driver/swap_debugfs.h> +#include <master/swap_debugfs.h> +#include <master/swap_initializer.h> #include <us_manager/sspt/sspt_proc.h> #include "debugfs_us_manager.h" @@ -64,6 +65,8 @@ static ssize_t read_tasks(struct file *file, char __user *user_buf, static const struct file_operations fops_tasks = { .owner = THIS_MODULE, + .open = swap_init_simple_open, + .release = swap_init_simple_release, .read = read_tasks, .llseek = default_llseek }; @@ -97,7 +100,7 @@ int init_debugfs_us_manager(void) { struct dentry *swap_dir, *dentry; - swap_dir = get_swap_debugfs_dir(); + swap_dir = swap_debugfs_getdir(); if (swap_dir == NULL) return -ENOENT; diff --git a/us_manager/helper.c b/us_manager/helper.c index 68599996..ec9c1a68 100644 --- a/us_manager/helper.c +++ b/us_manager/helper.c @@ -650,69 +650,50 @@ void unregister_helper_bottom(void) * * @return Error code */ -int init_helper(void) +int once_helper(void) { - unsigned long addr; + const char *sym; - addr = swap_ksyms("do_page_fault"); - if (addr == 0) { - printk("Cannot find address for handle_mm_fault function!\n"); - return -EINVAL; - } - mf_kretprobe.kp.addr = (kprobe_opcode_t *)addr; + sym = "do_page_fault"; + mf_kretprobe.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym); + if (mf_kretprobe.kp.addr == NULL) + goto not_found; - addr = swap_ksyms_substr("copy_process"); - if (addr == 0) { - printk("Cannot find address for copy_process function!\n"); - return -EINVAL; - } - cp_kretprobe.kp.addr = (kprobe_opcode_t *)addr; + sym = "copy_process"; + cp_kretprobe.kp.addr = (kprobe_opcode_t *)swap_ksyms_substr(sym); + if (cp_kretprobe.kp.addr == NULL) + goto not_found; - addr = swap_ksyms("mm_release"); - if (addr == 0) { - printk("Cannot find address for mm_release function!\n"); - return -EINVAL; - } - mr_kprobe.addr = (kprobe_opcode_t *)addr; + sym = "mm_release"; + mr_kprobe.addr = (kprobe_opcode_t *)swap_ksyms(sym); + if (mr_kprobe.addr == NULL) + goto not_found; - addr = swap_ksyms("do_munmap"); - if (addr == 0) { - printk("Cannot find address for do_munmap function!\n"); - return -EINVAL; - } - unmap_kretprobe.kp.addr = (kprobe_opcode_t *)addr; + sym = "do_munmap"; + unmap_kretprobe.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym); + if (unmap_kretprobe.kp.addr == NULL) + goto not_found; - addr = swap_ksyms("do_mmap_pgoff"); - if (addr == 0) { - printk("Cannot find address for do_mmap_pgoff function!\n"); - return -EINVAL; - } - mmap_kretprobe.kp.addr = (kprobe_opcode_t *)addr; + sym = "do_mmap_pgoff"; + mmap_kretprobe.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym); + if (mmap_kretprobe.kp.addr == NULL) + goto not_found; - addr = swap_ksyms("set_task_comm"); - if (addr == 0) { - printk("Cannot find address for set_task_comm function!\n"); - return -EINVAL; - } - comm_kretprobe.kp.addr = (kprobe_opcode_t *)addr; + sym = "set_task_comm"; + comm_kretprobe.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym); + if (comm_kretprobe.kp.addr == NULL) + goto not_found; #ifdef CONFIG_ARM - addr = swap_ksyms("ret_to_user"); - if (addr == 0) { - printk("Cannot find address for ret_to_user function!\n"); - return -EINVAL; - } - ctx_task_kprobe.addr = (kprobe_opcode_t *)addr; + sym = "ret_to_user"; + ctx_task_kprobe.addr = (kprobe_opcode_t *)swap_ksyms(sym); + if (ctx_task_kprobe.addr == NULL) + goto not_found; #endif /* CONFIG_ARM */ return 0; -} -/** - * @brief Uninitialization of helper - * - * @return Void - */ -void uninit_helper(void) -{ +not_found: + printk("ERROR: symbol '%s' not found\n", sym); + return -ESRCH; } diff --git a/us_manager/helper.h b/us_manager/helper.h index 475195d0..515717a7 100644 --- a/us_manager/helper.h +++ b/us_manager/helper.h @@ -31,8 +31,7 @@ static inline int is_kthread(struct task_struct *task) return !task->mm; } -int init_helper(void); -void uninit_helper(void); +int once_helper(void); int register_helper(void); void unregister_helper_top(void); diff --git a/us_manager/us_manager.c b/us_manager/us_manager.c index 08e9adc1..8d5d8a1a 100644 --- a/us_manager/us_manager.c +++ b/us_manager/us_manager.c @@ -31,6 +31,7 @@ #include "debugfs_us_manager.h" #include <writer/event_filter.h> +#include <master/swap_initializer.h> /* FIXME: move /un/init_msg() elsewhere and remove this include */ #include <writer/swap_writer_module.h> /* for /un/init_msg() */ @@ -209,50 +210,31 @@ static void exit_us_filter(void) -static int __init init_us_manager(void) +static int init_us_manager(void) { int ret; ret = init_us_filter(); if (ret) - goto us_filter_init_fail; - - init_msg(32*1024); - - ret = init_helper(); - if (ret) - goto helper_init_fail; + return ret; - ret = init_debugfs_us_manager(); + ret = init_msg(32*1024); /* TODO: move to writer */ if (ret) - goto debugfs_init_fail; - - return 0; + exit_us_filter(); -debugfs_init_fail: - uninit_helper(); - -helper_init_fail: - uninit_msg(); - exit_us_filter(); - -us_filter_init_fail: return ret; } -static void __exit exit_us_manager(void) +static void exit_us_manager(void) { if (status == ST_ON) do_usm_stop(); - exit_debugfs_us_manager(); uninit_msg(); - uninit_helper(); exit_us_filter(); } -module_init(init_us_manager); -module_exit(exit_us_manager); +SWAP_LIGHT_INIT_MODULE(once_helper, init_us_manager, exit_us_manager, + init_debugfs_us_manager, exit_debugfs_us_manager); MODULE_LICENSE ("GPL"); - diff --git a/writer/debugfs_writer.c b/writer/debugfs_writer.c index a09cd373..8cac36da 100644 --- a/writer/debugfs_writer.c +++ b/writer/debugfs_writer.c @@ -33,7 +33,8 @@ #include <linux/vmalloc.h> #include <linux/slab.h> #include <asm/uaccess.h> -#include <driver/swap_debugfs.h> +#include <master/swap_debugfs.h> +#include <master/swap_initializer.h> #include "swap_writer_module.h" #include "event_filter.h" @@ -101,6 +102,8 @@ put_buf: static const struct file_operations fops_raw = { .owner = THIS_MODULE, + .open = swap_init_simple_open, + .release = swap_init_simple_release, .write = write_raw, .llseek = default_llseek }; @@ -157,6 +160,8 @@ static ssize_t read_af(struct file *file, char __user *user_buf, static const struct file_operations fops_available_filters = { .owner = THIS_MODULE, + .open = swap_init_simple_open, + .release = swap_init_simple_release, .read = read_af, .llseek = default_llseek }; @@ -215,6 +220,8 @@ static ssize_t write_filter(struct file *file, const char __user *user_buf, static const struct file_operations fops_filter = { .owner = THIS_MODULE, + .open = swap_init_simple_open, + .release = swap_init_simple_release, .read = read_filter, .write = write_filter, .llseek = default_llseek @@ -259,7 +266,7 @@ int init_debugfs_writer(void) if (ret) return ret; - swap_dir = get_swap_debugfs_dir(); + swap_dir = swap_debugfs_getdir(); if (swap_dir == NULL) return -ENOENT; diff --git a/writer/swap_writer_module.c b/writer/swap_writer_module.c index d5353163..0a8fa892 100644 --- a/writer/swap_writer_module.c +++ b/writer/swap_writer_module.c @@ -42,6 +42,7 @@ #include <asm/uaccess.h> +#include <master/swap_initializer.h> #include <buffer/swap_buffer_module.h> #include <buffer/swap_buffer_errors.h> @@ -1460,6 +1461,7 @@ EXPORT_SYMBOL_GPL(custom_exit_event); + /* ============================================================================ * = WEB APP EVENT = * ============================================================================ @@ -1615,29 +1617,12 @@ put_current_buf_return: } EXPORT_SYMBOL_GPL(exit_web_event); -static int __init swap_writer_module_init(void) -{ - int ret; - ret = event_filter_init(); - if (ret) - return ret; - ret = init_debugfs_writer(); - if (ret) - event_filter_exit(); - return ret; -} - -static void __exit swap_writer_module_exit(void) -{ - exit_debugfs_writer(); - event_filter_exit(); -} -module_init(swap_writer_module_init); -module_exit(swap_writer_module_exit); +SWAP_LIGHT_INIT_MODULE(NULL, event_filter_init, event_filter_exit, + init_debugfs_writer, exit_debugfs_writer); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SWAP Writer module"); |