summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Aksenov <a.aksenov@samsung.com>2013-05-28 18:46:36 +0400
committerAlexander Aksenov <a.aksenov@samsung.com>2013-05-28 18:46:36 +0400
commit43e4fda67ea97afaf8204a32ad9e1d915cffdc90 (patch)
tree7ea12367d58c5fc6b0609ea5112822fbfff51286
parent035ab7da56300cc7711b8e1813c8d13bdf11da5b (diff)
downloadswap-modules-43e4fda67ea97afaf8204a32ad9e1d915cffdc90.tar.gz
swap-modules-43e4fda67ea97afaf8204a32ad9e1d915cffdc90.tar.bz2
swap-modules-43e4fda67ea97afaf8204a32ad9e1d915cffdc90.zip
[FEATURE] SWAP Buffer implemented
-rw-r--r--buffer/Kbuild6
-rw-r--r--buffer/Makefile27
-rw-r--r--buffer/Makefile.am34
-rw-r--r--buffer/buffer.c284
-rw-r--r--buffer/buffer.h9
-rw-r--r--buffer/buffer_description.h40
-rw-r--r--buffer/buffer_queue.c680
-rw-r--r--buffer/buffer_queue.h46
-rw-r--r--buffer/space_dep_operations.c148
-rw-r--r--buffer/space_dep_operations.h50
-rw-r--r--buffer/space_dep_types_and_def.h188
-rw-r--r--buffer/swap_buffer_module.c317
-rw-r--r--buffer/swap_buffer_module.h48
-rw-r--r--buffer/swap_buffer_to_buffer_queue.h27
14 files changed, 1574 insertions, 330 deletions
diff --git a/buffer/Kbuild b/buffer/Kbuild
index 34c249a9..6374b174 100644
--- a/buffer/Kbuild
+++ b/buffer/Kbuild
@@ -1,4 +1,4 @@
-EXTRA_CFLAGS := $(extra_cflags)
-
obj-m := swap_buffer.o
-swap_buffer-y := buffer.o
+
+swap_buffer-y := swap_buffer_module.o buffer_queue.o space_dep_operations.o
+
diff --git a/buffer/Makefile b/buffer/Makefile
new file mode 100644
index 00000000..b9d835ff
--- /dev/null
+++ b/buffer/Makefile
@@ -0,0 +1,27 @@
+USER_OBJECTS := buffer_queue_user.o swap_buffer_user.o space_dep_operations_user.o
+USER_FLAG := BUFFER_FOR_USER
+KERNEL_OBJECTS := buffer_queue.o swap_buffer_module.o space_dep_operations.o
+KERNEL_FILES := swap_buffer.o swap_buffer.mod.c swap_buffer.mod.o
+obj-m = $(KERNEL_OBJECTS)
+#CC=gcc
+CC=/home/alexander/dev/u1_slp/arm-linux-gnueabi-gcc4.4.1-glibc2.11.1/bin/arm-none-linux-gnueabi-gcc
+KERNEL_PATH=/home/alexander/dev/u1_slp/kernel_20121005
+#KERNEL_PATH=/home/alexander/vanilla_kernels/linux-3.8.6
+
+kernel:
+ make ARCH=arm CROSS_COMPILE=/home/alexander/dev/u1_slp/arm-linux-gnueabi-gcc4.4.1-glibc2.11.1/bin/arm-none-linux-gnueabi- -C $(KERNEL_PATH) SUBDIRS=$(PWD) modules
+
+libswap_buffer.so: $(USER_OBJECTS)
+ $(CC) -shared -lpthread -Wl,-soname,libswap_buffer.so -o libswap_buffer.so $(USER_OBJECTS)
+
+swap_buffer_user.o: swap_buffer_module.c
+ $(CC) -c -fPIC swap_buffer_module.c -D$(USER_FLAG) -o swap_buffer_user.o
+
+buffer_queue_user.o: buffer_queue.c
+ $(CC) -c -fPIC buffer_queue.c -D$(USER_FLAG) -o buffer_queue_user.o
+
+space_dep_operations_user.o: space_dep_operations.c
+ $(CC) -c -fPIC space_dep_operations.c -D$(USER_FLAG) -o space_dep_operations_user.o
+
+clean:
+ rm $(USER_OBJECTS) $(KERNEL_OBJECTS) $(KERNEL_FILES)
diff --git a/buffer/Makefile.am b/buffer/Makefile.am
deleted file mode 100644
index 4e450431..00000000
--- a/buffer/Makefile.am
+++ /dev/null
@@ -1,34 +0,0 @@
-if DEBUG
-debug_opt = -D__DEBUG
-endif
-
-if SPARSE
-sparse_output = C=2
-endif
-
-board_opt = -DBOARD_@BOARD@
-
-target_kernel_src = @KERNEL@
-target_arch = @ARCH@
-module_dir = $(realpath $(srcdir))
-module_name = swap_buffer
-cross_compiler = $(subst gcc,,$(CC))
-
-inlude_opt = -I$(top_srcdir)/src/modules/ksyms -I$(top_srcdir)/src/common -I$(top_srcdir)/src/profile
-extra_cflags = "$(inlude_opt) -DEC_ARCH_$(ARCH) $(debug_opt) $(board_opt)"
-
-#bin_SCRIPTS = patchko.sh insmod.sh
-
-all-local:
- cp $(top_srcdir)/src/modules/kprobe/Module.symvers $(module_dir)
- $(MAKE) CROSS_COMPILE=$(cross_compiler) ARCH=$(target_arch) extra_cflags=$(extra_cflags) $(AM_MAKEFLAGS) -C $(target_kernel_src) $(sparse_output) M=$(module_dir) modules
-
- echo "generate data for version patching <$(OBJDUMP)><$(READELF)>"
- $(top_srcdir)/src/modules/driver/patchko.sh -g $(module_dir)/$(module_name).ko $(OBJDUMP) $(READELF)
-
-clean-local:
- $(MAKE) CROSS_COMPILE=$(cross_compiler) ARCH=$(target_arch) $(AM_MAKEFLAGS) -C $(target_kernel_src) M=$(module_dir) clean
-
-install-exec-local:
- install -m 644 $(module_dir)/$(module_name).ko $(prefix)
- install -m 644 $(module_dir)/$(module_name).ko.addr $(prefix)
diff --git a/buffer/buffer.c b/buffer/buffer.c
deleted file mode 100644
index 52f4e389..00000000
--- a/buffer/buffer.c
+++ /dev/null
@@ -1,284 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/vmalloc.h>
-#include <linux/cdev.h>
-#include <linux/list.h>
-#include <linux/fs.h>
-#include <asm/uaccess.h>
-#include "buffer.h"
-
-#define BUF_DEBUG
-
-#ifdef BUF_DEBUG
-#define DPRINTF(format, args...) \
- do { \
- char *f = strrchr(__FILE__, '/'); \
- printk("%s[%s:%u:%s]: " format "\n", BUF_DEVICE, f ? f + 1: __FILE__, \
- __LINE__, __FUNCTION__, ##args); \
- } while (0)
-#else /* !BUF_DEBUG */
-#define DPRINTF(format, args...)
-#endif /* BUF_DEBUG */
-
-#define EPRINTF(format, args...) \
- do { \
- printk("%s: " format "\n", BUF_DEVICE, ##args); \
- } while (0)
-
-struct chunk {
- struct list_head list;
- unsigned long size;
- void *payload;
-};
-
-struct buffer_device {
- struct list_head free_chunks;
- struct list_head used_chunks;
- spinlock_t lock;
- struct cdev cdev;
- dev_t dev;
- unsigned long size;
- unsigned long chunk_size;
- char *buf;
-};
-
-static int buf_open(struct inode *, struct file *);
-static int buf_release(struct inode *, struct file *);
-static int buf_mmap(struct file *, struct vm_area_struct *);
-static ssize_t buf_read(struct file *, char __user *, size_t, loff_t *);
-static ssize_t buf_write(struct file *, const char __user *, size_t, loff_t *);
-static long buf_ioctl(struct file *, unsigned int, unsigned long);
-static unsigned int buf_poll(struct file *, struct poll_table_struct *);
-static ssize_t buf_splice_read(struct file *, loff_t *,
- struct pipe_inode_info *, size_t, unsigned int);
-static ssize_t buf_splice_write(struct pipe_inode_info *, struct file *,
- loff_t *, size_t, unsigned int);
-
-static struct file_operations buf_fops = {
- .owner = THIS_MODULE,
- .open = buf_open,
- .release = buf_release,
- .mmap = buf_mmap,
- .read = buf_read,
- .write = buf_write,
- .unlocked_ioctl = buf_ioctl,
- .poll = buf_poll,
- .splice_read = buf_splice_read,
- .splice_write = buf_splice_write
-};
-
-static struct buffer_device bdevice = {
- .free_chunks = LIST_HEAD_INIT(bdevice.free_chunks),
- .used_chunks = LIST_HEAD_INIT(bdevice.used_chunks),
- .lock = __SPIN_LOCK_UNLOCKED(bdevice.lock),
- .dev = MKDEV(BUF_DEFAULT_MAJOR, BUF_DEFAULT_MAJOR),
- .size = 0,
- .chunk_size = 0,
- .buf = NULL
-};
-
-/* --- chunks manipulation routines --- */
-static inline void *buf_get_free_chunk(void)
-{
- if (!list_empty(&bdevice.free_chunks))
- return list_first_entry(&bdevice.free_chunks, struct chunk, list);
-
- return NULL;
-}
-
-static inline void *buf_get_used_chunk(void)
-{
- if (!list_empty(&bdevice.used_chunks))
- return list_first_entry(&bdevice.used_chunks, struct chunk, list);
-
- return NULL;
-}
-
-static inline void buf_free_chunk(struct chunk *chunk)
-{
- list_move_tail(&chunk->list, &bdevice.free_chunks);
- chunk->size = 0;
-}
-
-static inline void buf_use_chunk(struct chunk *chunk)
-{
- list_move_tail(&chunk->list, &bdevice.used_chunks);
- chunk->size = 0;
-}
-
-static inline int buf_check_chunk_size(struct chunk *chunk, unsigned long size)
-{
- return (bdevice.chunk_size - chunk->size <= size);
-}
-
-static inline unsigned long buf_copy_to_chunk(struct chunk *chunk,
- const char __user *buf, size_t length)
-{
- return copy_from_user(chunk->payload, buf, length);
-}
-
-static inline unsigned long buf_copy_from_chunk(struct chunk *chunk,
- char __user *buf, size_t length)
-{
- return copy_to_user(buf, chunk->payload, length);
-}
-
-/* --- buffer manipulation routines */
-static inline void *buf_get_chunk(int i)
-{
- return (((struct chunk *)bdevice.buf) + i); //TODO FIXME!!!!
-}
-
-static int buf_init(unsigned long size, unsigned long chunk_size)
-{
- int retval = 0;
-
- INIT_LIST_HEAD(&bdevice.free_chunks);
- INIT_LIST_HEAD(&bdevice.used_chunks);
- bdevice.size = 0;
- bdevice.chunk_size = 0;
-
- bdevice.buf = vmalloc(size);
- if (!bdevice.buf) {
- retval = -ENOMEM;
- goto out;
- }
-
- /*for (;;) { //TODO
- struct chunk *chunk = buf_get_chunk(i); //TODO
- list_add_tail(&chunk->list, &bdevice.free_chunks);
- }*/
-
-out:
- return retval;
-}
-
-static int buf_free(void)
-{
- INIT_LIST_HEAD(&bdevice.free_chunks);
- INIT_LIST_HEAD(&bdevice.used_chunks);
- bdevice.size = 0;
- bdevice.chunk_size = 0;
-
- if (bdevice.buf)
- vfree(bdevice.buf);
- bdevice.buf = NULL;
-
- return 0;
-}
-
-/* --- char dev file operations --- */
-static int buf_open(struct inode *inode, struct file *filp)
-{
- /*struct buffer_device *dev = NULL; //TODO
-
- if (filp->f_flags & O_WRONLY) {
- }
-
- if ((filp->f_flags & O_ACCMODE) == O_WRONLY) {
- }
-
- if (!atomic_dec_and_test()) {
- //TODO
- return -EBUSY;
- }
-
- filp->private_data = dev;*/
- DPRINTF("");
- return 0;
-}
-
-static int buf_release(struct inode *inode, struct file *filp)
-{
- DPRINTF("");
- return 0;
-}
-
-static int buf_mmap(struct file *filp, struct vm_area_struct *vma)
-{
- EPRINTF("mmap() operation is not supported");
- return -ENODEV;
-}
-
-static ssize_t buf_read(struct file *filp, char __user *buf, size_t length,
- loff_t *offset)
-{
- DPRINTF("");
- return 0;
-}
-
-static ssize_t buf_write(struct file *filp, const char __user *buf,
- size_t length, loff_t *offset)
-{
- DPRINTF("");
- return length;
-}
-
-static long buf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-{
- DPRINTF("");
- return 0;
-}
-
-static unsigned int buf_poll(struct file *filp, struct poll_table_struct *table)
-{
- DPRINTF("");
- return 0;
-}
-
-static ssize_t buf_splice_read(struct file *filp, loff_t *offset,
- struct pipe_inode_info *pipe, size_t length, unsigned int flags)
-{
- DPRINTF("");
- return 0;
-}
-
-static ssize_t buf_splice_write(struct pipe_inode_info *pipe, struct file *filp,
- loff_t *offset, size_t length, unsigned int flags)
-{
- DPRINTF("");
- return 0;
-}
-
-/* --- module init/exit routines --- */
-static int __init buf_module_init(void)
-{
- int retval = 0;
-
- bdevice.dev = MKDEV(BUF_DEFAULT_MAJOR, BUF_DEFAULT_MINOR);
-
- retval = alloc_chrdev_region(&bdevice.dev, BUF_DEFAULT_MINOR,
- BUF_NUM_DEVICES, BUF_DEVICE);
- if (retval < 0) {
- EPRINTF("(%d) - alloc_chrdev_region", retval);
- goto out;
- }
-
- cdev_init(&bdevice.cdev, &buf_fops);
- bdevice.cdev.owner = THIS_MODULE;
- bdevice.cdev.ops = &buf_fops;
-
- retval = cdev_add(&bdevice.cdev, bdevice.dev, BUF_NUM_DEVICES);
- if (retval < 0) {
- EPRINTF("(%d) - cdev_add", retval);
- goto out;
- }
-
-out:
- DPRINTF("major = %d", MAJOR(bdevice.dev));
- return retval;
-}
-
-static void __exit buf_module_exit(void)
-{
- DPRINTF("major = %d", MAJOR(bdevice.dev));
- cdev_del(&bdevice.cdev);
- unregister_chrdev_region(bdevice.dev, BUF_NUM_DEVICES);
-}
-
-module_init(buf_module_init);
-module_exit(buf_module_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SWAP buffer module");
diff --git a/buffer/buffer.h b/buffer/buffer.h
deleted file mode 100644
index 82857771..00000000
--- a/buffer/buffer.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef BUFFER_H
-#define BUFFER_H
-
-#define BUF_DEFAULT_MAJOR 0
-#define BUF_DEFAULT_MINOR 0
-#define BUF_NUM_DEVICES 1
-#define BUF_DEVICE "swap_buffer"
-
-#endif /* BUFFER_H */
diff --git a/buffer/buffer_description.h b/buffer/buffer_description.h
new file mode 100644
index 00000000..49b77ceb
--- /dev/null
+++ b/buffer/buffer_description.h
@@ -0,0 +1,40 @@
+/*
+ * SWAP Buffer Module
+ * modules/buffer/swap_buffer_module.c
+ *
+ * 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, 2013
+ *
+ * 2013 Alexander Aksenov <a.aksenov@samsung.com>: SWAP Buffer implement
+ *
+ */
+
+/* SWAP Buffer structure description */
+
+#ifndef __BUFFER_DESCRIPTION_H__
+#define __BUFFER_DESCRIPTION_H__
+
+#include "space_dep_types_and_def.h"
+
+struct swap_buffer {
+ struct swap_buffer* next_in_queue; // Next buffer in queue
+ size_t full_buffer_part; // Buffer length
+ swap_subbuffer_ptr buffer; // Points to subbuffers virt mem(user)
+ // or to subbuffers first page(kernel)
+ buffer_rw_sync_type buffer_sync; // Buffer sync primitive
+};
+
+#endif /* __BUFFER_DESCRIPTION_H__ */
diff --git a/buffer/buffer_queue.c b/buffer/buffer_queue.c
new file mode 100644
index 00000000..7869f106
--- /dev/null
+++ b/buffer/buffer_queue.c
@@ -0,0 +1,680 @@
+/*
+ * SWAP Buffer Module
+ * modules/buffer/swap_buffer_module.c
+ *
+ * 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, 2013
+ *
+ * 2013 Alexander Aksenov <a.aksenov@samsung.com>: SWAP Buffer implement
+ *
+ */
+
+/* SWAP buffer queues implementation */
+
+/* For all memory allocation/deallocation operations, except buffer memory
+ * allocation/deallocation should be used
+ * memory_allocation(size_t memory_size)
+ * memory_free(void* ptr)
+ * defines.
+ * For subbuffer allocation/deallocation operations should be used
+ * buffer_allocation(size_t subbuffer_size)
+ * buffer_free(void *ptr, size_t subbuffer_size)
+ * To get buffer pointer for any usage, EXCEPT ALLOCATION AND DEALLOCATION
+ * use the following define:
+ * buffer_pointer(void *ptr_to_buffer_element_of_swap_buffer_structure)
+ * DO NOT USE SUBBUFFER PTR IN STRUCT SWAP_BUFFER WITHOUT THIS DEFINE!
+ * It will be ok for user space, but fail in kernel space.
+ *
+ * See space_dep_types_and_def.h for details */
+
+
+
+#include "buffer_queue.h"
+#include "buffer_description.h"
+#include "swap_buffer_to_buffer_queue.h"
+#include "space_dep_operations.h"
+
+typedef struct swap_buffer* write_start_ptr_type;
+typedef struct swap_buffer* write_end_ptr_type;
+typedef struct swap_buffer* read_start_ptr_type;
+typedef struct swap_buffer* read_end_ptr_type;
+
+static write_start_ptr_type queue_write_start_ptr = NULL; //Points to the
+ //write queue first
+ //element
+static write_end_ptr_type queue_write_end_ptr = NULL; //Points to the
+ //write queue last
+ //element
+static read_start_ptr_type queue_read_start_ptr = NULL; //Points to the read
+ //queue first
+ //element
+static read_end_ptr_type queue_read_end_ptr = NULL; //Points to the read
+ //queue last element
+static struct swap_buffer** queue_busy = NULL; //Pointers array. Points
+ //to occupied buffers
+static unsigned int queue_busy_last_element; //Store last occupied
+ //element in queue_busy
+static unsigned int queue_subbuffer_count = 0; //Subbuffers count
+static size_t queue_subbuffer_size = 0; //Subbuffers size
+static buffer_access_sync_type buffer_read_sync; //add_to_read_list and
+ //get_from_read_list
+ //sync
+static buffer_access_sync_type buffer_write_sync; //add_to_write_list and
+ //get_from_write_list
+ //sync
+static buffer_access_sync_type buffer_busy_sync; //add_to_busy_list and
+ //remove_from_busy_list
+ //sync
+static int pages_order_in_subbuffer = 0; //Page count in one
+ //subbuffer
+
+
+int buffer_queue_allocation(const size_t subbuffer_size,
+ const unsigned int subbuffers_count)
+{
+ int result = 0;
+ int i;
+
+ /* 0 - ok
+ * -1 - memory for queue_busy wasn't allocated
+ * -2 - memory for swap_buffer structure wasn't allocated
+ * -3 - memory for buffer wasn't allocated
+ * -4 - semaphore cannot be inited
+ * -5 - sync primitives cannot be inited
+ */
+
+ /* Static varibles initialization */
+ queue_subbuffer_size = subbuffer_size;
+ queue_subbuffer_count = subbuffers_count;
+ queue_busy_last_element = 0;
+
+ /* Set variable pages_in_subbuffer. It is used for allocation and
+ * deallocation memory pages and its value is returned from
+ * swap_buffer_get() and contains page count in one subbuffer.
+ * All this useful only in kernel space. In userspace it is dummy.*/
+ set_pages_order_in_subbuffer(queue_subbuffer_size);
+
+ /* Sync primitives initialization */
+ if (buffer_access_init(&buffer_read_sync)) {
+ result = -5;
+ return result;
+ }
+ if (buffer_access_init(&buffer_write_sync)) {
+ result = -5;
+ return result;
+ }
+ if (buffer_access_init(&buffer_busy_sync)) {
+ result = -5;
+ return result;
+ }
+
+ /* Memory allocation for queue_busy */
+ queue_busy = memory_allocation(sizeof(struct swap_buffer*) *
+ queue_subbuffer_count);
+
+ if (!queue_busy) {
+ result = -1;
+ return result;
+ }
+
+ /* Memory allocation for swap_buffer structures */
+ /* Allocation for first structure. */
+
+ queue_write_start_ptr = memory_allocation(sizeof(struct swap_buffer));
+
+ if (!queue_write_start_ptr) {
+ result = -2;
+ memory_free(queue_busy);
+ queue_busy = NULL;
+ return result;
+ }
+ queue_write_end_ptr = queue_write_start_ptr;
+
+ queue_write_end_ptr->next_in_queue = NULL;
+ queue_write_end_ptr->full_buffer_part = 0;
+ queue_write_end_ptr->buffer = buffer_allocation(queue_subbuffer_size);
+ if (!queue_write_end_ptr->buffer) {
+ print_err("Cannot allocate memory for buffer 1\n");
+ result = -3;
+ memory_free(queue_busy);
+ memory_free(queue_write_start_ptr);
+ queue_write_start_ptr = NULL;
+ queue_busy = NULL;
+
+ return result;
+ }
+
+ print_msg(" Buffer allocated = 0x%x\n", (unsigned long)queue_write_end_ptr->buffer);
+
+ if (buffer_rw_init(&queue_write_end_ptr->buffer_sync) != 0) {
+ result = -4;
+ memory_free(queue_busy);
+ queue_busy = NULL;
+ memory_free(queue_write_start_ptr);
+ queue_write_start_ptr = NULL;
+ return result;
+ }
+
+ /* Buffer initialization */
+ memset(buffer_address(queue_write_end_ptr->buffer), 0, queue_subbuffer_size);
+
+ /* Allocation for other structures. */
+ for (i = 1; i < queue_subbuffer_count; i++) {
+ queue_write_end_ptr->next_in_queue = memory_allocation(sizeof(struct swap_buffer));
+ if (!queue_write_end_ptr->next_in_queue) {
+ /* Free all previously allocated memory */
+ int j;
+ struct swap_buffer *clean_tmp_struct = queue_write_start_ptr;
+
+ result = -2;
+ for (j = 0; j < i; j++) {
+ clean_tmp_struct = queue_write_start_ptr;
+ if (queue_write_start_ptr != queue_write_end_ptr) {
+ queue_write_start_ptr = queue_write_start_ptr->next_in_queue;
+ }
+ buffer_free(clean_tmp_struct->buffer,queue_subbuffer_size);
+ memory_free(clean_tmp_struct);
+ }
+ queue_write_end_ptr = NULL;
+ queue_write_start_ptr = NULL;
+ memory_free(queue_busy);
+ queue_busy = NULL;
+ return result;
+ }
+
+ /* Now next queue_write_end_ptr is next */
+ queue_write_end_ptr = queue_write_end_ptr->next_in_queue;
+
+ queue_write_end_ptr->next_in_queue = NULL;
+ queue_write_end_ptr->full_buffer_part = 0;
+ queue_write_end_ptr->buffer = buffer_allocation(queue_subbuffer_size);
+ if (!queue_write_end_ptr->buffer) {
+ /* Free all previously allocated memory */
+ int j;
+ struct swap_buffer *clean_tmp_struct = queue_write_start_ptr;
+
+ result = -3;
+ print_err("Cannot allocate memory for buffer %d\n", i+1);
+
+ for (j = 0; j < i; j++) {
+ clean_tmp_struct = queue_write_start_ptr;
+ if (queue_write_start_ptr != queue_write_end_ptr) {
+ queue_write_start_ptr = queue_write_start_ptr->next_in_queue;
+ buffer_free(clean_tmp_struct->buffer, queue_subbuffer_size);
+ }
+ memory_free(clean_tmp_struct);
+ }
+ queue_write_end_ptr = NULL;
+ queue_write_start_ptr = NULL;
+ memory_free(queue_busy);
+ queue_busy = NULL;
+ return result;
+ }
+
+ print_msg(" Buffer allocated = 0x%x, pages_order = %d\n", (unsigned long)queue_write_end_ptr->buffer, pages_order_in_subbuffer);
+
+ if (buffer_rw_init(&queue_write_end_ptr->buffer_sync) != 0) {
+ /* Free all previously allocated memory */
+ int j;
+ struct swap_buffer *clean_tmp_struct = queue_write_start_ptr;
+
+ result = -4;
+ for (j = 0; j < i; j++) {
+ clean_tmp_struct = queue_write_start_ptr;
+ if (queue_write_start_ptr != queue_write_end_ptr) {
+ queue_write_start_ptr = queue_write_start_ptr->next_in_queue;
+ }
+ buffer_free(clean_tmp_struct->buffer, queue_subbuffer_size);
+ memory_free(clean_tmp_struct);
+ }
+ queue_write_end_ptr = NULL;
+ queue_write_start_ptr = NULL;
+ memory_free(queue_busy);
+ queue_busy = NULL;
+ return result;
+ }
+
+ /* Buffer initialization */
+ memset(buffer_address(queue_write_end_ptr->buffer), 0,
+ queue_subbuffer_size);
+ }
+
+ return result;
+}
+
+int buffer_queue_free(void)
+{
+ int result = 0;
+ struct swap_buffer* tmp = NULL;
+
+ /* 0 - ok
+ * <0 - set_all_to_read_list() error
+ */
+
+ //TODO Lock read list semaphore to prevent getting subbuffer from read list
+ /* Set all write buffers to read list */
+ result = set_all_to_read_list();
+
+ if (result < 0) {
+ return result;
+ }
+
+ /* Free buffers and structures memory that are in read list */
+ while (queue_read_start_ptr) {
+ tmp = queue_read_start_ptr;
+ queue_read_start_ptr = queue_read_start_ptr->next_in_queue;
+ buffer_free(tmp->buffer, queue_subbuffer_size);
+ memory_free(tmp);
+ }
+
+ /* Free busy_list */
+ memory_free(queue_busy);
+ queue_busy = NULL;
+
+ queue_subbuffer_size = 0;
+ queue_subbuffer_count = 0;
+ queue_read_start_ptr = NULL;
+ queue_read_end_ptr = NULL;
+ queue_write_start_ptr = NULL;
+ queue_write_end_ptr = NULL;
+
+ return result;
+}
+
+static unsigned int is_buffer_enough(struct swap_buffer* subbuffer, size_t size)
+{
+ return ((queue_subbuffer_size-subbuffer->full_buffer_part) >= size) ? 1 : 0;
+}
+
+/* Get first subbuffer from read list */
+struct swap_buffer* get_from_read_list(void)
+{
+ struct swap_buffer* result = NULL;
+
+ /* Lock read sync primitive */
+ if (buffer_access_lock(&buffer_read_sync)) {
+ return NULL;
+ }
+
+ if (queue_read_start_ptr == NULL) {
+ result = NULL;
+ goto get_from_read_list_unlock;
+ }
+
+ result = queue_read_start_ptr;
+
+ /* If this is the last readable buffer, queue_read_start_ptr next time will
+ * points to NULL and that case is handled in the beginning of function
+ */
+ if (queue_read_start_ptr == queue_read_end_ptr) {
+ queue_read_end_ptr = NULL;
+ }
+ queue_read_start_ptr = queue_read_start_ptr->next_in_queue;
+
+get_from_read_list_unlock:
+ /* Unlock read sync primitive */
+ if (buffer_access_unlock(&buffer_read_sync)) {
+ return NULL;
+ }
+
+ return result;
+}
+
+/* Add subbuffer to read list */
+int add_to_read_list(struct swap_buffer* subbuffer)
+{
+ int result = 0;
+
+ /* 0 - ok
+ * 1 - cannot lock
+ * 2 - cannot unlock */
+
+ /* Lock read sync primitive */
+ if (buffer_access_lock(&buffer_read_sync)) {
+ result = 1;
+ return result;
+ }
+
+ // TODO Sanitization?
+ if (!queue_read_start_ptr) {
+ queue_read_start_ptr = subbuffer;
+ }
+
+ if (queue_read_end_ptr) {
+ queue_read_end_ptr->next_in_queue = subbuffer;
+
+ queue_read_end_ptr = queue_read_end_ptr->next_in_queue;
+ } else {
+ queue_read_end_ptr = subbuffer;
+ }
+ queue_read_end_ptr->next_in_queue = NULL;
+
+ /* Unlock read sync primitive */
+ if (buffer_access_unlock(&buffer_read_sync)) {
+ result = 2;
+ return result;
+ }
+
+ return result;
+}
+
+/* Call add to read list and callback function from driver module */
+int add_to_read_list_with_callback(struct swap_buffer* subbuffer)
+{
+ int result = 0;
+
+ result = add_to_read_list(subbuffer);
+ // TODO Handle ret value
+ swap_buffer_callback(subbuffer);
+
+ return result;
+}
+
+/* Get first writable subbuffer from write list */
+struct swap_buffer* get_from_write_list(size_t size)
+{
+ struct swap_buffer *result = NULL;
+
+ /* Callbacks are called at the end of the function to prevent deadlocks */
+ struct swap_buffer *queue_callback_start_ptr = NULL;
+ struct swap_buffer *queue_callback_end_ptr = NULL;
+ struct swap_buffer *tmp_buffer = NULL;
+
+ /* Lock write list sync primitive */
+ if (buffer_access_lock(&buffer_write_sync)) {
+ return NULL;
+ }
+
+ while (queue_write_start_ptr) {
+ /* If start points to NULL => list is empty => exit */
+ if (!queue_write_start_ptr) {
+ result = NULL;
+ goto get_from_write_list_unlock;
+ }
+
+ /* Get semaphore value. Useful only if we want buffer to write to
+ * several buffers the same time
+ *
+ * We're trying to lock semaphore, and if it is successful, unlocking
+ * it. Otherwise, going to the next step. */
+ if (buffer_rw_lock(&queue_write_start_ptr->buffer_sync) != 0) {
+ // TODO HOW? HOW is it possible to get there?!
+ result = queue_write_start_ptr;
+ /* If we reached end of the list */
+ if (queue_write_start_ptr == queue_write_end_ptr) {
+ queue_write_end_ptr = NULL;
+ }
+ /* Move start write pointer */
+ queue_write_start_ptr = queue_write_start_ptr->next_in_queue;
+
+ /* Add to callback list */
+ if (!queue_callback_start_ptr) {
+ queue_callback_start_ptr = result;
+ }
+ if (queue_callback_end_ptr) {
+ queue_callback_end_ptr->next_in_queue = result;
+ }
+ queue_callback_end_ptr = result;
+ queue_callback_end_ptr->next_in_queue = NULL;
+
+ result = NULL;
+ continue;
+ }
+ buffer_rw_unlock(&queue_write_start_ptr->buffer_sync);
+
+// TODO Do something
+
+ if (is_buffer_enough(queue_write_start_ptr, size)) {
+ result = queue_write_start_ptr;
+ break;
+ } else {
+ /* If size is not enough, subbuffers goes to read list */
+ result = queue_write_start_ptr;
+ /* If we reached end of the list */
+ if (queue_write_start_ptr == queue_write_end_ptr) {
+ queue_write_end_ptr = NULL;
+ }
+ /* Move start write pointer */
+ queue_write_start_ptr = queue_write_start_ptr->next_in_queue;
+
+ /* Add to callback list */
+ if (!queue_callback_start_ptr) {
+ queue_callback_start_ptr = result;
+ }
+ if (queue_callback_end_ptr) {
+ queue_callback_end_ptr->next_in_queue = result;
+ }
+ queue_callback_end_ptr = result;
+ queue_callback_end_ptr->next_in_queue = NULL;
+
+ result = NULL;
+ }
+ }
+
+ /* Lock writing semaphore */
+ if (result) {
+ if (buffer_rw_lock(&result->buffer_sync)) {
+ result = NULL;
+ goto get_from_write_list_unlock;
+ }
+ }
+
+get_from_write_list_unlock:
+ /* Unlock write list sync primitive */
+ if (buffer_access_unlock(&buffer_write_sync)) {
+ if (result) {
+ buffer_rw_unlock(&result->buffer_sync);
+ }
+ return NULL;
+ }
+
+ /* Adding buffers to read list and calling callbacks */
+ for (tmp_buffer = NULL; queue_callback_start_ptr; ) {
+
+ if (queue_callback_start_ptr == queue_callback_end_ptr) {
+ queue_callback_end_ptr = NULL;
+ }
+ tmp_buffer = queue_callback_start_ptr;
+ queue_callback_start_ptr = queue_callback_start_ptr->next_in_queue;
+
+ add_to_read_list_with_callback(tmp_buffer);
+ }
+
+ return result;
+}
+
+/* Add subbuffer to write list */
+int add_to_write_list(struct swap_buffer* subbuffer)
+{
+ /* 0 - ok
+ * -1 - cannot lock
+ * -2 - cannot unlock */
+
+ if (buffer_access_lock(&buffer_write_sync)) {
+ return -1;
+ }
+
+ /* Reinitialize */
+ memset(buffer_address(subbuffer->buffer), 0, queue_subbuffer_size);
+ subbuffer->full_buffer_part = 0;
+
+ if (!queue_write_start_ptr) {
+ queue_write_start_ptr = subbuffer;
+ }
+
+ if (queue_write_end_ptr) {
+ queue_write_end_ptr->next_in_queue = subbuffer;
+ queue_write_end_ptr = queue_write_end_ptr->next_in_queue;
+ } else {
+ queue_write_end_ptr = subbuffer;
+ }
+ queue_write_end_ptr->next_in_queue = NULL;
+
+ if (buffer_access_unlock(&buffer_write_sync)) {
+ return -2;
+ }
+
+ return 0;
+}
+
+/* Add subbuffer to busy list when it is read from out of the buffer */
+int add_to_busy_list(struct swap_buffer* subbuffer)
+{
+ /* 0 - ok
+ * -1 - cannot lock
+ * -2 - cannot unlock */
+
+ /* Lock busy sync primitive */
+ if (buffer_access_lock(&buffer_busy_sync)) {
+ return -1;
+ }
+
+ subbuffer->next_in_queue = NULL;
+ queue_busy[queue_busy_last_element] = subbuffer;
+ queue_busy_last_element += 1;
+
+ /* Unlock busy sync primitive */
+ if (buffer_access_unlock(&buffer_busy_sync)) {
+ return -2;
+ }
+
+ return 0;
+}
+
+/* Remove subbuffer from busy list when it is released */
+int remove_from_busy_list(struct swap_buffer* subbuffer)
+{
+ int result = -1; // For sanitization
+ int i;
+
+ /* 0 - ok
+ * -1 - no such buffer in queue_busy list
+ * -2 - cannot lock
+ * -3 - cannot unlock
+ */
+
+ /* Lock busy list sync primitive */
+ if (buffer_access_lock(&buffer_busy_sync)) {
+ result = -2;
+ return result;
+ }
+
+ /* Sanitization and removing */
+ for (i = 0; i < queue_busy_last_element; i++) {
+ if (queue_busy[i] == subbuffer) {
+ /* Last element goes here and length is down 1 */
+ queue_busy[i] = queue_busy[queue_busy_last_element - 1];
+ queue_busy_last_element -= 1;
+ result = 0;
+ break;
+ }
+ }
+
+ /* Unlock busy list sync primitive */
+ if (buffer_access_unlock(&buffer_busy_sync)) {
+ result = -3;
+ return result;
+ }
+
+ return result;
+}
+
+/* Get subbuffers count in read list */
+/* XXX Think about locks */
+int get_full_buffers_count(void)
+{
+ int result = 0;
+ struct swap_buffer* buffer = queue_read_start_ptr;
+
+ /* >=0 - buffers count
+ */
+
+ while (buffer && buffer->full_buffer_part) {
+ result += 1;
+ buffer = buffer->next_in_queue;
+ }
+
+ return result;
+}
+
+/* Set all subbuffers in write list to read list */
+int set_all_to_read_list(void)
+{
+ int result = 0;
+ struct swap_buffer *buffer = queue_write_start_ptr;
+
+ /* 0 - ok
+ * -1 - sem_wait() error
+ * -2 - sem_post() error
+ * -3 - problems with locking sync primitives
+ * -4 - problems with unlocking sync primitives
+ */
+
+ /* Locking write sync primitive */
+ if (buffer_access_lock(&buffer_write_sync)) {
+ result = -3;
+ return result;
+ }
+
+ while (queue_write_start_ptr) {
+ /* Waiting till semaphore should be posted */
+
+// TODO To think: It's not bad as it is, but maybe it would be better locking
+// semaphore while changing its list? (Not bad now, cause buffer should have
+// already been stopped).
+
+ if (buffer_rw_lock(&buffer->buffer_sync)) {
+ result = -1;
+ goto set_all_to_read_list_unlock;
+ }
+
+ if (buffer_rw_unlock(&buffer->buffer_sync)) {
+ result = -2;
+ goto set_all_to_read_list_unlock;
+ }
+
+ buffer = queue_write_start_ptr;
+
+ /* If we reached end of the list */
+ if (queue_write_start_ptr == queue_write_end_ptr) {
+ queue_write_end_ptr = NULL;
+ }
+ queue_write_start_ptr = queue_write_start_ptr->next_in_queue;
+
+ add_to_read_list(buffer);
+ }
+
+set_all_to_read_list_unlock:
+ /* Unlocking write primitive */
+ if (buffer_access_unlock(&buffer_write_sync)) {
+ result = -4;
+ }
+ return result;
+}
+
+/* Get subbuffers count in busy list */
+/* XXX Think abount lock */
+int get_busy_buffers_count(void)
+{
+ return queue_busy_last_element;
+}
+
+/* Get memory pages count in subbuffer */
+int get_pages_in_subbuffer(void)
+{
+/* Return 1 if pages order 0, or 2 of power pages_order_in_subbuffer otherwise */
+ return (pages_order_in_subbuffer) ? 2 << (pages_order_in_subbuffer - 1) : 1;
+}
diff --git a/buffer/buffer_queue.h b/buffer/buffer_queue.h
new file mode 100644
index 00000000..daf8044f
--- /dev/null
+++ b/buffer/buffer_queue.h
@@ -0,0 +1,46 @@
+/*
+ * SWAP Buffer Module
+ * modules/buffer/swap_buffer_module.c
+ *
+ * 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, 2013
+ *
+ * 2013 Alexander Aksenov <a.aksenov@samsung.com>: SWAP Buffer implement
+ *
+ */
+
+/* SWAP Buffer queues interface */
+
+#ifndef __BUFFER_QUEUE_HEADER__
+#define __BUFFER_QUEUE_HEADER__
+
+#include "buffer_description.h"
+
+int buffer_queue_allocation(size_t subbuffer_size, unsigned int subbuffers_count);
+int buffer_queue_free(void);
+struct swap_buffer* get_from_write_list(size_t size);
+struct swap_buffer* get_from_read_list(void);
+int add_to_write_list(struct swap_buffer* subbuffer);
+int add_to_read_list(struct swap_buffer* subbuffer);
+int add_to_busy_list(struct swap_buffer* subbuffer);
+int remove_from_busy_list(struct swap_buffer* subbuffer);
+int get_full_buffers_count(void);
+
+int set_all_to_read_list(void);
+int get_busy_buffers_count(void);
+int get_pages_in_subbuffer(void);
+
+#endif /* __BUFFER_QUEUE_HEADER__ */
diff --git a/buffer/space_dep_operations.c b/buffer/space_dep_operations.c
new file mode 100644
index 00000000..77a97cfe
--- /dev/null
+++ b/buffer/space_dep_operations.c
@@ -0,0 +1,148 @@
+/*
+ * SWAP Buffer Module
+ * modules/buffer/swap_buffer_module.c
+ *
+ * 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, 2013
+ *
+ * 2013 Alexander Aksenov <a.aksenov@samsung.com>: SWAP Buffer implement
+ *
+ */
+
+/* Space-depended operations: memory allocations and synchronizations.
+ * This makes swap_buffer buildable both as a kernel module and a library. */
+
+#ifdef BUFFER_FOR_USER
+
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#else /* BUFFER_FOR_USER */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+
+unsigned long flags; // Flags for spinlocks
+
+#endif /* BUFFER_FOR_USER */
+
+
+#include "space_dep_operations.h"
+
+
+
+/* For access sync primitives we use pthread_mutex for user space and
+ * spin_locks for kernel space */
+
+inline int buffer_access_init(buffer_access_sync_type *buffer_sync)
+{
+#ifdef BUFFER_FOR_USER
+ return pthread_mutex_init(buffer_sync, NULL);
+#else /* BUFFER_FOR_USER */
+ spin_lock_init(buffer_sync);
+ return 0;
+#endif /* BUFFER_FOR_USER */
+}
+
+inline int buffer_access_lock(buffer_access_sync_type *buffer_sync)
+{
+#ifdef BUFFER_FOR_USER
+ return pthread_mutex_lock(buffer_sync);
+#else /* BUFFER_FOR_USER */
+ spin_lock_irqsave(buffer_sync, flags);
+ return 0;
+#endif /* BUFFER_FOR_USER */
+}
+
+inline int buffer_access_unlock(buffer_access_sync_type *buffer_sync)
+{
+#ifdef BUFFER_FOR_USER
+ return pthread_mutex_unlock(buffer_sync);
+#else /* BUFFER_FOR_USER */
+ spin_unlock_irqrestore(buffer_sync, flags);
+ return 0;
+#endif /* BUFFER_FOR_USER */
+}
+
+
+/* For buffer RW sync primitives in kernel space we use spinlocks as we do it
+ * for access sync primitives, so, if building for kernel, buffer_access
+ * functions are called. */
+
+inline int buffer_rw_init(buffer_rw_sync_type *buffer_rw)
+{
+#ifdef BUFFER_FOR_USER
+ return sem_init(buffer_rw, 0, 1);
+#else /* BUFFER_FOR_USER */
+ return buffer_access_init(buffer_rw);
+#endif /* BUFFER_FOR_USER */
+}
+
+inline int buffer_rw_lock(buffer_rw_sync_type *buffer_rw)
+{
+#ifdef BUFFER_FOR_USER
+ return sem_wait(buffer_rw);
+#else /* BUFFER_FOR_USER */
+ return buffer_access_lock(buffer_rw);
+#endif /* BUFFER_FOR_USER */
+}
+
+inline int buffer_rw_unlock(buffer_rw_sync_type *buffer_rw)
+{
+#ifdef BUFFER_FOR_USER
+ return sem_post(buffer_rw);
+#else /* BUFFER_FOR_USER */
+ return buffer_access_unlock(buffer_rw);
+#endif /* BUFFER_FOR_USER */
+}
+
+#ifndef BUFFER_FOR_USER
+
+inline unsigned int nearest_power_of_two(unsigned int number)
+{
+ unsigned int result = 0;
+ unsigned int two_to_the_power = 1;
+
+ /* If aligned_size == PAGE_SIZE we need only one page, so return 0 */
+ if (number == 1) {
+ return result;
+ }
+
+ while (two_to_the_power < number) {
+ two_to_the_power <<= 1;
+ result++;
+ }
+
+ return result;
+}
+
+inline unsigned int get_order_for_alloc_pages(size_t memory_size)
+{
+ /* First evaluate remainder of the division memory_size by PAGE_SIZE.
+ * If memory_size is divisible by PAGE_SIZE, then remainder equals 0. */
+ size_t remainder = (memory_size % PAGE_SIZE) ?
+ (memory_size % PAGE_SIZE) : PAGE_SIZE;
+
+ /* Align memory_size to the PAGE_SIZE. aligned_size >= memory_size */
+ size_t aligned_size = memory_size + (PAGE_SIZE - remainder);
+
+ return nearest_power_of_two(aligned_size / PAGE_SIZE);
+}
+
+#endif /* BUFFER_FOR_USER */
+
diff --git a/buffer/space_dep_operations.h b/buffer/space_dep_operations.h
new file mode 100644
index 00000000..d8d789d7
--- /dev/null
+++ b/buffer/space_dep_operations.h
@@ -0,0 +1,50 @@
+/*
+ * SWAP Buffer Module
+ * modules/buffer/swap_buffer_module.c
+ *
+ * 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, 2013
+ *
+ * 2013 Alexander Aksenov <a.aksenov@samsung.com>: SWAP Buffer implement
+ *
+ */
+
+/* Space-depended operations file header.
+ * This makes swap_buffer buildable both as a kernel module and a library. */
+
+#ifndef __SPACE_DEPENDED_OPERATIONS_FILE_HEADER__
+#define __SPACE_DEPENDED_OPERATIONS_FILE_HEADER__
+
+#include "space_dep_types_and_def.h"
+
+inline int buffer_access_init(buffer_access_sync_type *buffer_sync);//Buffer
+ //access
+ //sync
+ //primitives
+ //init
+inline int buffer_access_lock(buffer_access_sync_type *buffer_sync);//Lock sync
+ //primitive
+inline int buffer_access_unlock(buffer_access_sync_type *buffer_sync);//Unlock
+ //sync
+ //primitive
+inline int buffer_rw_init(buffer_rw_sync_type *buffer_rw); //Init read-write
+ //sync primitive
+inline int buffer_rw_lock(buffer_rw_sync_type *buffer_rw); //Lock read-write
+ //sync primitive
+inline int buffer_rw_unlock(buffer_rw_sync_type *buffer_rw); //Unlock read-write
+ //sync primitive
+
+#endif /* __SPACE_DEPENDED_OPERATIONS_FILE_HEADER__ */
diff --git a/buffer/space_dep_types_and_def.h b/buffer/space_dep_types_and_def.h
new file mode 100644
index 00000000..6965bcdc
--- /dev/null
+++ b/buffer/space_dep_types_and_def.h
@@ -0,0 +1,188 @@
+/*
+ * SWAP Buffer Module
+ * modules/buffer/swap_buffer_module.c
+ *
+ * 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, 2013
+ *
+ * 2013 Alexander Aksenov <a.aksenov@samsung.com>: SWAP Buffer implement
+ *
+ */
+
+/* Space-depended types and defines.
+ * This makes swap_buffer buildable both as a kernel module and as a library.*/
+
+#ifndef __SPACE_DEPENDEND_TYPES_AND_DEFINES_FILE_HEADER__
+#define __SPACE_DEPENDEND_TYPES_AND_DEFINES_FILE_HEADER__
+
+#ifdef BUFFER_FOR_USER
+
+#include <semaphore.h>
+#include <pthread.h>
+#include <string.h>
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#else /* BUFFER_FOR_USER */
+
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/mm.h>
+
+#endif /*BUFFER_FOR_USER */
+
+
+/* Functions for alloc_pages */
+#ifndef BUFFER_FOR_USER
+
+inline unsigned int nearest_power_of_two(unsigned int number);
+inline unsigned int get_order_for_alloc_pages(size_t memory_size);
+
+#endif /* BUFFER_FOR_USER */
+
+
+
+/* Synchronization primitives with the same interface for different context */
+#ifdef BUFFER_FOR_USER
+
+typedef sem_t buffer_rw_sync_type; // Read-write sync
+typedef pthread_mutex_t buffer_access_sync_type;// Pointer manipulations sync
+
+#else /* BUFFER_FOR_USER */
+
+typedef spinlock_t buffer_rw_sync_type; // Read-write sync
+typedef spinlock_t buffer_access_sync_type; // Pointer manipulations sync
+
+#endif /*BUFFER_FOR_USER */
+
+
+/* Subbuffer type */
+#ifdef BUFFER_FOR_USER
+
+typedef void* swap_subbuffer_ptr;
+
+#else /* BUFFER_FOR_USER */
+
+/* If buffer supposed to work in kernel space, it's very useful to
+ * store buffer page struct ptr */
+typedef struct page* swap_subbuffer_ptr;
+
+#endif /* BUFFER_FOR_USER */
+
+
+/* Memory and buffer operations */
+#ifdef BUFFER_FOR_USER
+
+#define memory_allocation(memory_size) malloc(memory_size)
+#define memory_free(ptr) free(ptr)
+#define buffer_allocation(memory_size) malloc(memory_size)
+#define buffer_free(ptr, subbuf_size) free(ptr)
+#define buffer_address(buffer_ptr) buffer_ptr
+
+#else /* BUFFER_FOR_USER */
+
+#define memory_allocation(memory_size) kmalloc(memory_size, GFP_KERNEL)
+#define memory_free(ptr) kfree(ptr)
+#define buffer_allocation(memory_size) \
+ alloc_pages(GFP_KERNEL, (pages_order_in_subbuffer >= 0) ? \
+ pages_order_in_subbuffer : \
+ get_order_for_alloc_pages(memory_size))
+#define buffer_free(ptr, subbuf_size) \
+ __free_pages(ptr, (pages_order_in_subbuffer >= 0) ? \
+ pages_order_in_subbuffer : \
+ get_order_for_alloc_pages(subbuf_size))
+// TODO Check whether it is correct for several pages
+#define buffer_address(buffer_ptr) page_address(buffer_ptr)
+
+#endif /* BUFFER_FOR_USER */
+
+
+/* Set pages_order_in_subbuffer variable. Used only in kernel space */
+#ifdef BUFFER_FOR_USER
+
+#define set_pages_order_in_subbuffer(memory_size) \
+ pages_order_in_subbuffer = 0
+
+#else /* BUFFER_FOR_USER */
+
+#define set_pages_order_in_subbuffer(memory_size) \
+ pages_order_in_subbuffer = get_order_for_alloc_pages(memory_size)
+
+#endif /* BUFFER_FOR_USER */
+
+
+/* Kernel module specific functions */
+#ifdef BUFFER_FOR_USER
+
+#define SWAP_BUFFER_MODULE_INFORMATION
+
+#else /* BUFFER_FOR_USER */
+
+#define SWAP_BUFFER_MODULE_INFORMATION \
+static int __init swap_buffer_module_init(void) \
+{ \
+ printk(KERN_NOTICE "SWAP_BUFFER : Buffer module initialized\n"); \
+ return 0; \
+} \
+ \
+static void __exit swap_buffer_module_exit(void) \
+{ \
+ printk(KERN_NOTICE "SWAP_BUFFER : Buffer module unintialized\n"); \
+} \
+ \
+module_init(swap_buffer_module_init); \
+module_exit(swap_buffer_module_exit);
+
+#endif /* BUFFER_FOR_USER */
+
+
+/* Message printing */
+#ifdef BUFFER_FOR_USER
+
+#define print_debug(msg, args...) \
+ printf("SWAP_BUFFER DEBUG : " msg, ##args)
+#define print_msg(msg, args...) \
+ printf("SWAP_BUFFER : " msg, ##args)
+#define print_warn(msg, args...) \
+ printf("SWAP_BUFFER WARNING : " msg, ##args)
+#define print_err(msg, args...) \
+ printf("SWAP_BUFFER ERROR : " msg, ##args)
+#define print_crit(msg, args...) \
+ printf("SWAP_BUFFER CRITICAL : " msg, ##args)
+
+#else /* BUFFER_FOR_USER */
+
+#define print_debug(msg, args...) \
+ printk(KERN_DEBUG "SWAP_BUFFER DEBUG : " msg, ##args)
+#define print_msg(msg, args...) \
+ printk(KERN_INFO "SWAP_BUFFER : " msg, ##args)
+#define print_warn(msg, args...) \
+ printk(KERN_WARNING "SWAP_BUFFER WARNING : " msg, ##args)
+#define print_err(msg, args...) \
+ printk(KERN_ERR "SWAP_BUFFER ERROR : " msg, ##args)
+#define print_crit(msg, args...) \
+ printk(KERN_CRIT "SWAP_BUFFER CRITICAL : " msg, ##args)
+
+#endif /* BUFFER_FOR_USER */
+
+#endif /* __SPACE_DEPENDEND_TYPES_AND_DEFINES_FILE_HEADER__ */
diff --git a/buffer/swap_buffer_module.c b/buffer/swap_buffer_module.c
new file mode 100644
index 00000000..539ec417
--- /dev/null
+++ b/buffer/swap_buffer_module.c
@@ -0,0 +1,317 @@
+/*
+ * SWAP Buffer Module
+ * modules/buffer/swap_buffer_module.c
+ *
+ * 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, 2013
+ *
+ * 2013 Alexander Aksenov <a.aksenov@samsung.com>: SWAP Buffer implement
+ *
+ */
+
+/* SWAP Buffer interface implementation */
+
+#include "swap_buffer_module.h"
+#include "buffer_queue.h"
+#include "buffer_description.h"
+#include "space_dep_operations.h"
+
+#define BUFFER_WORK 1
+#define BUFFER_STOP 0
+
+typedef int(*subbuffer_callback_type)(void*);
+typedef unsigned char buffer_status;
+
+static subbuffer_callback_type subbuffer_callback = NULL; //Callback, called
+ //when new readalbe
+ //subbuffer appears
+static size_t subbuffers_size = 0; //Subbuffers size
+static unsigned int subbuffers_num = 0; //Subbuffres count
+static buffer_status swap_buffer_status = BUFFER_STOP; //Buffer status
+
+//static buffer_access_sync_type buffer_sync;
+
+//TODO Swap restart
+
+static inline int are_two_regions_overlap(const void* region1,
+ const void* region2, size_t size)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ if ((region1 + i == region2) || (region1 + i == region2)) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int swap_buffer_init(size_t subbuffer_size, unsigned int nr_subbuffers,
+ int (*subbuffer_full_callback)(void))
+{
+ int result = 0;
+
+ /* >0 - mem pages in one subbuffer
+ */
+
+ // TODO Different initialization for first one and initialization after stop
+ // TODO Test if wrong function type
+ subbuffer_callback = (subbuffer_callback_type)subbuffer_full_callback;
+ subbuffers_size = subbuffer_size;
+ subbuffers_num = nr_subbuffers;
+
+ result = buffer_queue_allocation(subbuffers_size, subbuffers_num);
+ if (result < 0) {
+ return result;
+ }
+
+ swap_buffer_status = BUFFER_WORK;
+ result = get_pages_in_subbuffer();
+
+ return result;
+}
+
+int swap_buffer_uninit(void)
+{
+ int result;
+
+ /* 0 - ok
+ * -1 - not all buffers released
+ * 2 - mutex_destroy failed
+ */
+
+ /* Stop swap_buffer */
+ swap_buffer_status = BUFFER_STOP;
+
+ /* Checking whether all buffers are released */
+ if (get_busy_buffers_count()) {
+ result = -1;
+ return result;
+ }
+
+ /* Free */
+ result = buffer_queue_free();
+
+ subbuffer_callback = NULL;
+ subbuffers_size = 0;
+ subbuffers_num = 0;
+
+//TODO
+/*#ifdef BUFFER_FOR_USER
+ if (pthread_mutex_destroy(&buffer_sync)) {
+ result = 2;
+ return result;
+ }
+
+// TODO Think for spinlock*/
+//#endif /* BUFFER_FOR_USER */
+
+ return result;
+}
+
+ssize_t swap_buffer_write(size_t size, void* data)
+{
+ int result = 0;
+ struct swap_buffer* buffer_to_write = NULL;
+
+ /* >0 - ok, written size
+ * -1 - no buffers in write list
+ * -2 - wrong size
+ * -3 - swap_buffer stopped
+ * -4 - cannot lock semaphore
+ * -5 - cannot unlock semaphore
+ * -6 - regions are overlapping
+ */
+
+ /* Check buffer status */
+ if (!(swap_buffer_status & BUFFER_WORK)) {
+ result = -3;
+ return result;
+ }
+
+ /* Size sanitization */
+ if ((size > subbuffers_size) || (size == 0)) {
+ result = -2;
+ return result;
+ }
+
+ /* Get next write buffer and occupying semaphore */
+ buffer_to_write = get_from_write_list(size);
+ if (!buffer_to_write) {
+ result = -1;
+ return result;
+ }
+
+ /* Check for overlapping */
+ if (are_two_regions_overlap(buffer_address(buffer_to_write->buffer) +
+ buffer_to_write->full_buffer_part, data,
+ size)) {
+ result = -6;
+ goto buf_write_sem_post;
+ }
+
+ /* Copy data to buffer */
+ /* XXX Think of using memmove instead */
+ memcpy((void*)((unsigned long)(buffer_address(buffer_to_write->buffer)) +
+ buffer_to_write->full_buffer_part), data, size);
+
+ /* Inc buffer full part size */
+ buffer_to_write->full_buffer_part += size;
+
+ result = size;
+
+ /* Unlock semaphpore (Locked in get_from_write_list()) */
+buf_write_sem_post:
+ if (buffer_rw_unlock(&buffer_to_write->buffer_sync)) {
+ result = -5;
+ return result;
+ }
+
+ return result;
+}
+
+int swap_buffer_get(struct swap_buffer** subbuffer)
+{
+ int result = 0;
+ struct swap_buffer* buffer_to_read = NULL;
+
+ /* >0 - page count in subbuffer (in kernel) or 0 (in user)
+ * -1 - no buffer for reading
+ * -2 - problems with add_to_busy_list
+ */
+
+ /* Get next read buffer */
+ buffer_to_read = get_from_read_list();
+ if (!buffer_to_read) {
+ result = -1;
+ return result;
+ }
+
+ /* Add to busy list */
+ buffer_to_read->next_in_queue = NULL;
+ if (add_to_busy_list(buffer_to_read) < 0) {
+ result = -2;
+ return result;
+ }
+
+ // TODO Useless check
+ if (!result) {
+ *subbuffer = buffer_to_read;
+ }
+
+ return get_pages_in_subbuffer();
+}
+
+int swap_buffer_release(struct swap_buffer** subbuffer)
+{
+ int result = 0;
+
+ /* 0 - ok
+ * -1 - can't remove from busy list!
+ * -2 - can't add to write list
+ */
+
+ /* Remove from busy list (includes sanitization) */
+ if (remove_from_busy_list(*subbuffer) < 0) {
+ result = -1;
+ return result;
+ }
+
+ /* Add to write list */
+ if (add_to_write_list(*subbuffer) < 0) {
+ result = -2;
+ return result;
+ }
+
+ return result;
+}
+
+int swap_buffer_flush(struct swap_buffer ***subbuffers)
+{
+ int result = 0;
+
+ /* >=0 - buffers count
+ * <0 - set_all_to_read_list() error code
+ */
+
+ /* Stop swap_buffer */
+ swap_buffer_status = BUFFER_STOP;
+
+ /* Set all write buffers to read list */
+ result = set_all_to_read_list();
+ if (result < 0) {
+ return result;
+ }
+
+ /* Get count of all full buffers */
+ result = get_full_buffers_count();
+ if (result <= 0) {
+ result = 0;
+ return result;
+ }
+
+// Relict code, not used now. You can just enjoy how it was some time before.
+//
+// /* Memory allocation for swap_buffer structures array.
+// * Must be freed in module that called this one */
+// *subbuffers = memory_allocation(sizeof(struct swap_buffer*) * result);
+// if (!(*subbuffers)) {
+// result = -1;
+// return result;
+// }
+//
+// /* Adding all subbufers from read list to subbuffers array */
+// do {
+// i++;
+// (*subbuffers)[i] = get_from_read_list(); //TODO Are we need mutex?
+// //Buffer stopped - nobody's
+// //writing
+// } while ((*subbuffers)[i]);
+
+ return result;
+}
+
+int swap_buffer_callback(void *buffer)
+{
+ int result;
+
+ /* 0 - ok
+ * <0 - subbuffer_callback error
+ * -99 - subbuffer_callback is not registered */
+
+ if (!subbuffer_callback) {
+ return -99;
+ }
+
+ result = subbuffer_callback(buffer);
+ if (result < 0) {
+ print_err("Callback error! Error code: %d\n", result);
+ }
+
+ return result;
+}
+
+#ifndef BUFFER_FOR_USER
+EXPORT_SYMBOL_GPL(swap_buffer_init);
+EXPORT_SYMBOL_GPL(swap_buffer_uninit);
+EXPORT_SYMBOL_GPL(swap_buffer_write);
+EXPORT_SYMBOL_GPL(swap_buffer_get);
+EXPORT_SYMBOL_GPL(swap_buffer_release);
+EXPORT_SYMBOL_GPL(swap_buffer_flush);
+#endif /* BUFFER_FOR_USER */
+
+SWAP_BUFFER_MODULE_INFORMATION
diff --git a/buffer/swap_buffer_module.h b/buffer/swap_buffer_module.h
new file mode 100644
index 00000000..38c91745
--- /dev/null
+++ b/buffer/swap_buffer_module.h
@@ -0,0 +1,48 @@
+/*
+ * SWAP Buffer Module
+ * modules/buffer/swap_buffer_module.h
+ *
+ * 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, 2013
+ *
+ * 2013 Alexander Aksenov <a.aksenov@samsung.com>: SWAP Buffer implement
+ *
+ */
+
+/* SWAP Buffer interface description */
+
+#ifndef __SWAP_BUFFER_HEADER_H__
+#define __SWAP_BUFFER_HEADER_H__
+
+#include "buffer_description.h"
+
+int swap_buffer_init(size_t subbuffer_size, unsigned int nr_subbuffers,
+ int (*subbuffer_full_callback)(void));
+
+int swap_buffer_uninit(void);
+ssize_t swap_buffer_write(size_t size, void* data);
+
+int swap_buffer_get(struct swap_buffer **subbuffer);
+int swap_buffer_release(struct swap_buffer **subbuffer);
+
+/* Takes pointer to array of subbuffers pointers. Supposed to be NULL,
+ * allocation occures in buf_flush.
+ * BE AWARE!!! Function returns:
+ * =<0 - IF IT FINISHED UNSUCCESSFUL
+ * >0 - count of readable buffers */
+int swap_buffer_flush(struct swap_buffer ***subbuffer);
+
+#endif /* __SWAP_BUFFER_HEADER_H__ */
diff --git a/buffer/swap_buffer_to_buffer_queue.h b/buffer/swap_buffer_to_buffer_queue.h
new file mode 100644
index 00000000..91c2bbf6
--- /dev/null
+++ b/buffer/swap_buffer_to_buffer_queue.h
@@ -0,0 +1,27 @@
+/*
+ * SWAP Buffer Module
+ * modules/buffer/swap_buffer_module.c
+ *
+ * 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, 2013
+ *
+ * 2013 Alexander Aksenov <a.aksenov@samsung.com>: SWAP Buffer implement
+ *
+ */
+
+/* SWAP Buffer interface for buffer queue */
+
+void swap_buffer_callback(void* buffer);