2 * RelayFS buffer management code.
4 * Copyright (C) 2002-2005 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp
5 * Copyright (C) 1999-2005 - Karim Yaghmour (karim@opersys.com)
7 * This file is released under the GPL.
10 #include <linux/module.h>
11 #include <linux/vmalloc.h>
13 #include <linux/relayfs_fs.h>
18 * close() vm_op implementation for relayfs file mapping.
20 static void relay_file_mmap_close(struct vm_area_struct
*vma
)
22 struct rchan_buf
*buf
= vma
->vm_private_data
;
23 buf
->chan
->cb
->buf_unmapped(buf
, vma
->vm_file
);
27 * nopage() vm_op implementation for relayfs file mapping.
29 static struct page
*relay_buf_nopage(struct vm_area_struct
*vma
,
30 unsigned long address
,
34 struct rchan_buf
*buf
= vma
->vm_private_data
;
35 unsigned long offset
= address
- vma
->vm_start
;
37 if (address
> vma
->vm_end
)
38 return NOPAGE_SIGBUS
; /* Disallow mremap */
42 page
= vmalloc_to_page(buf
->start
+ offset
);
48 *type
= VM_FAULT_MINOR
;
54 * vm_ops for relay file mappings.
56 static struct vm_operations_struct relay_file_mmap_ops
= {
57 .nopage
= relay_buf_nopage
,
58 .close
= relay_file_mmap_close
,
62 * relay_mmap_buf: - mmap channel buffer to process address space
63 * @buf: relay channel buffer
64 * @vma: vm_area_struct describing memory to be mapped
66 * Returns 0 if ok, negative on error
68 * Caller should already have grabbed mmap_sem.
70 int relay_mmap_buf(struct rchan_buf
*buf
, struct vm_area_struct
*vma
)
72 unsigned long length
= vma
->vm_end
- vma
->vm_start
;
73 struct file
*filp
= vma
->vm_file
;
78 if (length
!= (unsigned long)buf
->chan
->alloc_size
)
81 vma
->vm_ops
= &relay_file_mmap_ops
;
82 vma
->vm_private_data
= buf
;
83 buf
->chan
->cb
->buf_mapped(buf
, filp
);
89 * relay_alloc_buf - allocate a channel buffer
90 * @buf: the buffer struct
91 * @size: total size of the buffer
93 * Returns a pointer to the resulting buffer, NULL if unsuccessful
95 static void *relay_alloc_buf(struct rchan_buf
*buf
, unsigned long size
)
98 unsigned int i
, j
, n_pages
;
100 size
= PAGE_ALIGN(size
);
101 n_pages
= size
>> PAGE_SHIFT
;
103 buf
->page_array
= kcalloc(n_pages
, sizeof(struct page
*), GFP_KERNEL
);
104 if (!buf
->page_array
)
107 for (i
= 0; i
< n_pages
; i
++) {
108 buf
->page_array
[i
] = alloc_page(GFP_KERNEL
);
109 if (unlikely(!buf
->page_array
[i
]))
112 mem
= vmap(buf
->page_array
, n_pages
, VM_MAP
, PAGE_KERNEL
);
116 memset(mem
, 0, size
);
117 buf
->page_count
= n_pages
;
121 for (j
= 0; j
< i
; j
++)
122 __free_page(buf
->page_array
[j
]);
123 kfree(buf
->page_array
);
128 * relay_create_buf - allocate and initialize a channel buffer
129 * @alloc_size: size of the buffer to allocate
130 * @n_subbufs: number of sub-buffers in the channel
132 * Returns channel buffer if successful, NULL otherwise
134 struct rchan_buf
*relay_create_buf(struct rchan
*chan
)
136 struct rchan_buf
*buf
= kcalloc(1, sizeof(struct rchan_buf
), GFP_KERNEL
);
140 buf
->padding
= kmalloc(chan
->n_subbufs
* sizeof(size_t *), GFP_KERNEL
);
144 buf
->start
= relay_alloc_buf(buf
, chan
->alloc_size
);
149 kref_get(&buf
->chan
->kref
);
159 * relay_destroy_buf - destroy an rchan_buf struct and associated buffer
160 * @buf: the buffer struct
162 void relay_destroy_buf(struct rchan_buf
*buf
)
164 struct rchan
*chan
= buf
->chan
;
167 if (likely(buf
->start
)) {
169 for (i
= 0; i
< buf
->page_count
; i
++)
170 __free_page(buf
->page_array
[i
]);
171 kfree(buf
->page_array
);
175 kref_put(&chan
->kref
, relay_destroy_channel
);
179 * relay_remove_buf - remove a channel buffer
181 * Removes the file from the relayfs fileystem, which also frees the
182 * rchan_buf_struct and the channel buffer. Should only be called from
185 void relay_remove_buf(struct kref
*kref
)
187 struct rchan_buf
*buf
= container_of(kref
, struct rchan_buf
, kref
);
188 relayfs_remove(buf
->dentry
);