Merge commit 'cc09f10e84d5' into kernel
[kernel/swap-modules.git] / driver / legacy.c
1 ////////////////////////////////////////////////////////////////////////////////////
2 //
3 //      FILE:           legacy.c
4 //
5 //      DESCRIPTION:
6 //      This file is C source for SWAP driver.
7 //
8 //      SEE ALSO:       legacy.h
9 //      AUTHOR:         L.Komkov
10 //      COMPANY NAME:   Samsung Research Center in Moscow
11 //      DEPT NAME:      Advanced Software Group
12 //      CREATED:        2008.02.15
13 //      VERSION:        1.0
14 //      REVISION DATE:  2008.12.02
15 //
16 ////////////////////////////////////////////////////////////////////////////////////
17
18 #include "module.h"
19 #include "legacy.h"
20
21 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
22 signed long
23 schedule_timeout_interruptible (signed long timeout)
24 {
25         __set_current_state (TASK_INTERRUPTIBLE);
26         return schedule_timeout (timeout);
27 }
28 #endif /* kernel without schedule_timeout_interruptible */
29
30 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
31 int
32 remap_vmalloc_range (struct vm_area_struct *vma, void *addr, unsigned long pgoff)
33 {
34         unsigned long uaddr = vma->vm_start;
35         unsigned long usize = vma->vm_end - vma->vm_start;
36         int ret = -EINVAL;
37
38         if ((PAGE_SIZE - 1) & (unsigned long) addr)
39         {
40                 return -EINVAL;
41         }
42
43         if (pgoff)
44         {
45                 return -EINVAL;
46         }
47
48         while (usize)
49         {
50                 ret = remap_pfn_range (vma, uaddr, vmalloc_to_pfn (addr), PAGE_SIZE, PAGE_SHARED);
51                 if (ret)
52                 {
53                         break;
54                 }
55                 uaddr += PAGE_SIZE;
56                 addr += PAGE_SIZE;
57                 usize -= PAGE_SIZE;
58         };
59
60         return ret;
61 }
62 #endif /* kernel without remap_vmalloc_range() */
63
64 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
65 /*
66     To be mappable to user space, pages of memory allocated via "vmalloc" must
67     be marked with "PG_reserved" flag. Memory allocated via "vmalloc_user"
68     doesn't need it.
69 */
70 static void
71 _reserve_pages (void *p, unsigned size)
72 {
73         unsigned pages = (size + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
74         while (pages)
75         {
76                 SetPageReserved (vmalloc_to_page (p));
77
78                 p += PAGE_SIZE;
79                 --pages;
80         }
81 }
82
83 static void
84 _unreserve_pages (void *p, unsigned size)
85 {
86         unsigned pages = (size + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
87         while (pages)
88         {
89                 ClearPageReserved (vmalloc_to_page (p));
90
91                 p += PAGE_SIZE;
92                 --pages;
93         }
94 }
95
96 void *
97 vmalloc_user (unsigned long size)
98 {
99         void *p = __vmalloc (size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL);
100         if (p)
101         {
102                 memset (p, 0, size);
103                 _reserve_pages (p, size);
104         }
105         return p;
106 }
107
108 void
109 vfree_user (void *address, unsigned long size)
110 {
111         _unreserve_pages (address, size);
112         vfree (address);
113 }
114 #endif /* kernel without vmalloc_user() */