2 * driver/device_driver.c
3 * @author Alexander Aksenov <a.aksenov@samsung.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 * Copyright (C) Samsung Electronics, 2013
25 * @section DESCRIPTION
27 * Provides SWAP device.
30 #include <linux/types.h>
32 #include <linux/cdev.h>
33 #include <linux/err.h>
34 #include <linux/device.h>
35 #include <linux/ioctl.h>
36 #include <linux/slab.h>
38 #include <linux/splice.h>
39 #include <linux/sched.h>
40 #include <linux/module.h>
41 #include <linux/wait.h>
42 #include <linux/workqueue.h>
43 #include <asm/uaccess.h>
45 #include <ksyms/ksyms.h>
46 #include <master/swap_initializer.h>
48 #include "device_driver.h"
49 #include "swap_driver_errors.h"
50 #include "driver_to_buffer.h"
51 #include "swap_ioctl.h"
52 #include "driver_defs.h"
53 #include "device_driver_to_driver_to_buffer.h"
54 #include "driver_to_buffer.h"
55 #include "driver_to_msg.h"
57 /** SWAP device name as it is in /dev/. */
58 #define SWAP_DEVICE_NAME "swap_device"
60 /** Maximum subbuffer size. Used for sanitization checks. */
61 #define MAXIMUM_SUBBUFFER_SIZE (64 * 1024)
63 /* swap_device driver routines */
64 static ssize_t swap_device_read(struct file *filp, char __user *buf,
65 size_t count, loff_t *f_pos);
66 static long swap_device_ioctl(struct file *filp, unsigned int cmd,
68 static ssize_t swap_device_splice_read(struct file *filp, loff_t *ppos,
69 struct pipe_inode_info *pipe, size_t len,
73 * @var swap_device_fops
74 * @brief SWAP device file operations.
76 const struct file_operations swap_device_fops = {
78 .read = swap_device_read,
79 .open = swap_init_simple_open,
80 .release = swap_init_simple_release,
81 .unlocked_ioctl = swap_device_ioctl,
82 .splice_read = swap_device_splice_read,
85 /* Typedefs for splice_* funcs. Prototypes are for linux-3.8.6 */
86 /** Splice to pipe pointer type. */
87 typedef ssize_t(*splice_to_pipe_p_t)(struct pipe_inode_info *pipe,
88 struct splice_pipe_desc *spd);
89 /** Splice grow spd pointer type. */
90 typedef int(*splice_grow_spd_p_t)(const struct pipe_inode_info *pipe,
91 struct splice_pipe_desc *spd);
93 static splice_to_pipe_p_t splice_to_pipe_p;
94 static splice_grow_spd_p_t splice_grow_spd_p;
96 static msg_handler_t msg_handler;
99 static dev_t swap_device_no;
101 /* Device cdev struct */
102 static struct cdev *swap_device_cdev;
104 /* Device class struct */
105 static struct class *swap_device_class;
107 /* Device device struct */
108 static struct device *swap_device_device;
110 /* Reading tasks queue */
111 static DECLARE_WAIT_QUEUE_HEAD(swap_device_wait);
114 static atomic_t flag_wake_up = ATOMIC_INIT(0);
116 static void __bottom_wake_up(void)
118 if (waitqueue_active(&swap_device_wait))
119 wake_up_interruptible(&swap_device_wait);
122 static void bottom_wake_up(struct work_struct *work)
124 if (atomic_read(&flag_wake_up)) {
125 atomic_set(&flag_wake_up, 0);
130 static DECLARE_WORK(w_wake_up, bottom_wake_up);
132 static void exit_w_wake_up(void)
134 flush_scheduled_work();
140 * @brief We need this realization of splice_shrink_spd() because its desing
141 * frequently changes in custom kernels.
143 * @param pipe Pointer to the pipe whereto splice data.
144 * @param spd Pointer to the splice_pipe_desc structure.
147 void swap_device_splice_shrink_spd(struct pipe_inode_info *pipe,
148 struct splice_pipe_desc *spd)
150 if (pipe->buffers <= PIPE_DEF_BUFFERS)
158 /* TODO Think of permanent major */
161 * @brief Register device.
163 * @return 0 on success, negative error code otherwise.
165 int swap_device_init(void)
169 /* Allocating device major and minor nums for swap_device */
170 result = alloc_chrdev_region(&swap_device_no, 0, 1, SWAP_DEVICE_NAME);
172 print_crit("Major number allocation has failed\n");
173 result = -E_SD_ALLOC_CHRDEV_FAIL;
177 /* Creating device class. Using IS_ERR, because class_create
178 * returns ERR_PTR on error. */
179 swap_device_class = class_create(THIS_MODULE, SWAP_DEVICE_NAME);
180 if (IS_ERR(swap_device_class)) {
181 print_crit("Class creation has failed\n");
182 result = -E_SD_CLASS_CREATE_FAIL;
186 /* Cdev allocation */
187 swap_device_cdev = cdev_alloc();
188 if (!swap_device_cdev) {
189 print_crit("Cdev structure allocation has failed\n");
190 result = -E_SD_CDEV_ALLOC_FAIL;
194 /* Cdev intialization and setting file operations */
195 cdev_init(swap_device_cdev, &swap_device_fops);
197 /* Adding cdev to system */
198 result = cdev_add(swap_device_cdev, swap_device_no, 1);
200 print_crit("Device adding has failed\n");
201 result = -E_SD_CDEV_ADD_FAIL;
205 /* Create device struct */
206 swap_device_device = device_create(swap_device_class, NULL,
208 "%s", SWAP_DEVICE_NAME);
209 if (IS_ERR(swap_device_device)) {
210 print_crit("Device struct creating has failed\n");
211 result = -E_SD_DEVICE_CREATE_FAIL;
215 /* Find splice_* funcs addresses */
216 splice_to_pipe_p = (splice_to_pipe_p_t)swap_ksyms("splice_to_pipe");
217 if (!splice_to_pipe_p) {
218 print_err("splice_to_pipe() not found!\n");
219 result = -E_SD_NO_SPLICE_FUNCS;
223 splice_grow_spd_p = (splice_grow_spd_p_t)swap_ksyms("splice_grow_spd");
224 if (!splice_grow_spd_p) {
225 print_err("splice_grow_spd() not found!\n");
226 result = -E_SD_NO_SPLICE_FUNCS;
233 if (swap_device_cdev)
234 cdev_del(swap_device_cdev);
235 if (swap_device_class)
236 class_destroy(swap_device_class);
238 unregister_chrdev_region(swap_device_no, 1);
242 /* TODO Check wether driver is registered */
245 * @brief Unregister device.
249 void swap_device_exit(void)
253 splice_to_pipe_p = NULL;
254 splice_grow_spd_p = NULL;
256 device_destroy(swap_device_class, swap_device_no);
257 cdev_del(swap_device_cdev);
258 class_destroy(swap_device_class);
259 unregister_chrdev_region(swap_device_no, 1);
262 static ssize_t swap_device_read(struct file *filp, char __user *buf,
263 size_t count, loff_t *f_pos)
265 /* Wait queue item that consists current task. It is used to be added in
266 * swap_device_wait queue if there is no data to be read. */
270 /* TODO : Think about spin_locks to prevent reading race condition. */
272 driver_to_buffer_next_buffer_to_read()) != E_SD_SUCCESS) {
274 /* Add process to the swap_device_wait queue and set the current
275 * task state TASK_INTERRUPTIBLE. If there is any data to be
276 * read, then the current task is removed from the
277 * swap_device_wait queue and its state is changed to this. */
278 prepare_to_wait(&swap_device_wait, &wait, TASK_INTERRUPTIBLE);
282 goto swap_device_read_error;
283 } else if (result == E_SD_NO_DATA_TO_READ) {
284 /* Yes, E_SD_NO_DATA_TO_READ should be positive,
285 * cause it's not really an error */
286 if (filp->f_flags & O_NONBLOCK) {
288 goto swap_device_read_error;
290 if (signal_pending(current)) {
291 result = -ERESTARTSYS;
292 goto swap_device_read_error;
295 finish_wait(&swap_device_wait, &wait);
299 result = driver_to_buffer_read(buf, count);
300 /* If there is an error - return 0 */
307 swap_device_read_error:
308 finish_wait(&swap_device_wait, &wait);
313 static long swap_device_ioctl(struct file *filp, unsigned int cmd,
319 case SWAP_DRIVER_BUFFER_INITIALIZE:
321 struct buffer_initialize initialize_struct;
323 result = copy_from_user(&initialize_struct, (void *)arg,
324 sizeof(struct buffer_initialize));
328 if (initialize_struct.size > MAXIMUM_SUBBUFFER_SIZE) {
329 print_err("Wrong subbuffer size\n");
330 result = -E_SD_WRONG_ARGS;
334 result = driver_to_buffer_initialize(initialize_struct.size,
335 initialize_struct.count);
337 print_err("Buffer initialization failed %d\n", result);
340 result = E_SD_SUCCESS;
344 case SWAP_DRIVER_BUFFER_UNINITIALIZE:
346 result = driver_to_buffer_uninitialize();
348 print_err("Buffer uninitialization failed %d\n",
352 case SWAP_DRIVER_NEXT_BUFFER_TO_READ:
354 /* Use this carefully */
355 result = driver_to_buffer_next_buffer_to_read();
356 if (result == E_SD_NO_DATA_TO_READ) {
357 /* TODO Do what we usually do when there are no
358 * subbuffers to read (make daemon sleep ?) */
362 case SWAP_DRIVER_FLUSH_BUFFER:
364 result = driver_to_buffer_flush();
367 case SWAP_DRIVER_MSG:
370 result = msg_handler((void __user *)arg);
372 print_warn("msg_handler() is not register\n");
377 case SWAP_DRIVER_WAKE_UP:
379 swap_device_wake_up_process();
380 result = E_SD_SUCCESS;
384 print_warn("Unknown command %d\n", cmd);
392 static void swap_device_pipe_buf_release(struct pipe_inode_info *inode,
393 struct pipe_buffer *pipe)
395 __free_page(pipe->page);
398 static void swap_device_page_release(struct splice_pipe_desc *spd,
401 __free_page(spd->pages[i]);
404 static const struct pipe_buf_operations swap_device_pipe_buf_ops = {
406 .map = generic_pipe_buf_map,
407 .unmap = generic_pipe_buf_unmap,
408 .confirm = generic_pipe_buf_confirm,
409 .release = swap_device_pipe_buf_release,
410 .steal = generic_pipe_buf_steal,
411 .get = generic_pipe_buf_get
414 static ssize_t swap_device_splice_read(struct file *filp, loff_t *ppos,
415 struct pipe_inode_info *pipe,
416 size_t len, unsigned int flags)
418 /* Wait queue item that consists current task. It is used to be added in
419 * swap_device_wait queue if there is no data to be read. */
423 struct page *pages[PIPE_DEF_BUFFERS];
424 struct partial_page partial[PIPE_DEF_BUFFERS];
425 struct splice_pipe_desc spd = {
428 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 5))
429 .nr_pages_max = PIPE_DEF_BUFFERS,
433 .ops = &swap_device_pipe_buf_ops,
434 .spd_release = swap_device_page_release,
437 /* Get next buffer to read */
438 /* TODO : Think about spin_locks to prevent reading race condition.*/
440 driver_to_buffer_next_buffer_to_read()) != E_SD_SUCCESS) {
442 /* Add process to the swap_device_wait queue and set the current
443 * task state TASK_INTERRUPTIBLE. If there is any data to be
444 * read, then the current task is removed from the
445 * swap_device_wait queue and its state is changed. */
446 prepare_to_wait(&swap_device_wait, &wait, TASK_INTERRUPTIBLE);
448 print_err("driver_to_buffer_next_buffer_to_read error "
450 /* TODO Error return to OS */
452 goto swap_device_splice_read_error;
453 } else if (result == E_SD_NO_DATA_TO_READ) {
454 if (filp->f_flags & O_NONBLOCK) {
456 goto swap_device_splice_read_error;
458 if (signal_pending(current)) {
459 result = -ERESTARTSYS;
460 goto swap_device_splice_read_error;
463 finish_wait(&swap_device_wait, &wait);
467 if (splice_grow_spd_p(pipe, &spd)) {
469 goto swap_device_splice_read_out;
472 result = driver_to_buffer_fill_spd(&spd);
474 print_err("Cannot fill spd for splice\n");
475 goto swap_device_shrink_spd;
478 result = splice_to_pipe_p(pipe, &spd);
480 swap_device_shrink_spd:
481 swap_device_splice_shrink_spd(pipe, &spd);
483 swap_device_splice_read_out:
486 swap_device_splice_read_error:
487 finish_wait(&swap_device_wait, &wait);
493 * @brief Wakes up daemon that splicing data from driver.
497 void swap_device_wake_up_process(void)
499 if (atomic_read(&flag_wake_up) == 0) {
500 atomic_set(&flag_wake_up, 1);
501 schedule_work(&w_wake_up);
506 * @brief Registers received message handler.
508 * @param mh Pointer to message handler.
511 void set_msg_handler(msg_handler_t mh)
515 EXPORT_SYMBOL_GPL(set_msg_handler);