VirtualBox

source: vbox/trunk/src/VBox/Additions/linux/sharedfolders/regops.c@ 6359

Last change on this file since 6359 was 6055, checked in by vboxsync, 17 years ago

vboxvfs: aio_read/aio_write is 2.6.0+ only

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.4 KB
Line 
1/** @file
2 *
3 * vboxvfs -- VirtualBox Guest Additions for Linux:
4 * Regular file inode and file operations
5 */
6
7/*
8 * Copyright (C) 2006-2007 innotek GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19/*
20 * Limitations: only COW memory mapping is supported
21 */
22
23#include "vfsmod.h"
24
25#define CHUNK_SIZE 4096
26
27/* fops */
28static int
29sf_reg_read_aux (const char *caller, struct sf_glob_info *sf_g,
30 struct sf_reg_info *sf_r, void *buf, uint32_t *nread,
31 uint64_t pos)
32{
33 int rc = vboxCallRead (&client_handle, &sf_g->map, sf_r->handle,
34 pos, nread, buf, false /* already locked? */);
35 if (VBOX_FAILURE (rc)) {
36 LogFunc(("vboxCallRead failed. caller=%s, rc=%Vrc\n",
37 caller, rc));
38 return -EPROTO;
39 }
40 return 0;
41}
42
43static ssize_t
44sf_reg_read (struct file *file, char *buf, size_t size, loff_t *off)
45{
46 int err;
47 void *tmp;
48 size_t left = size;
49 ssize_t total_bytes_read = 0;
50 struct inode *inode = file->f_dentry->d_inode;
51 struct sf_glob_info *sf_g = GET_GLOB_INFO (inode->i_sb);
52 struct sf_reg_info *sf_r = file->private_data;
53 loff_t pos = *off;
54
55 TRACE ();
56 if (!S_ISREG (inode->i_mode)) {
57 LogFunc(("read from non regular file %d\n", inode->i_mode));
58 return -EINVAL;
59 }
60
61 if (!size) {
62 return 0;
63 }
64
65 tmp = kmalloc (CHUNK_SIZE, GFP_KERNEL);
66 if (!tmp) {
67 LogRelFunc(("could not allocate bounce buffer memory %d bytes\n", CHUNK_SIZE));
68 return -ENOMEM;
69 }
70
71 while (left) {
72 uint32_t to_read, nread;
73
74 to_read = CHUNK_SIZE;
75 if (to_read > left) {
76 to_read = (uint32_t) left;
77 }
78 nread = to_read;
79
80 err = sf_reg_read_aux (__func__, sf_g, sf_r, tmp, &nread, pos);
81 if (err) {
82 goto fail;
83 }
84
85 if (copy_to_user (buf, tmp, nread)) {
86 err = -EFAULT;
87 goto fail;
88 }
89
90 pos += nread;
91 left -= nread;
92 buf += nread;
93 total_bytes_read += nread;
94 if (nread != to_read) {
95 break;
96 }
97 }
98
99 *off += total_bytes_read;
100 kfree (tmp);
101 return total_bytes_read;
102
103 fail:
104 kfree (tmp);
105 return err;
106}
107
108static ssize_t
109sf_reg_write (struct file *file, const char *buf, size_t size, loff_t *off)
110{
111 int err;
112 void *tmp;
113 size_t left = size;
114 ssize_t total_bytes_written = 0;
115 struct inode *inode = file->f_dentry->d_inode;
116 struct sf_inode_info *sf_i = GET_INODE_INFO (inode);
117 struct sf_glob_info *sf_g = GET_GLOB_INFO (inode->i_sb);
118 struct sf_reg_info *sf_r = file->private_data;
119 loff_t pos = *off;
120
121 TRACE ();
122 BUG_ON (!sf_i);
123 BUG_ON (!sf_g);
124 BUG_ON (!sf_r);
125
126 if (!S_ISREG (inode->i_mode)) {
127 LogFunc(("write to non regular file %d\n", inode->i_mode));
128 return -EINVAL;
129 }
130
131 if (!size) {
132 return 0;
133 }
134
135 tmp = kmalloc (CHUNK_SIZE, GFP_KERNEL);
136 if (!tmp) {
137 LogRelFunc(("could not allocate bounce buffer memory %d\n", CHUNK_SIZE));
138 return -ENOMEM;
139 }
140
141 while (left) {
142 int rc;
143 uint32_t to_write, nwritten;
144
145 to_write = CHUNK_SIZE;
146 if (to_write > left) {
147 to_write = (uint32_t) left;
148 }
149 nwritten = to_write;
150
151 if (copy_from_user (tmp, buf, to_write)) {
152 err = -EFAULT;
153 goto fail;
154 }
155
156 rc = vboxCallWrite (&client_handle, &sf_g->map, sf_r->handle,
157 pos, &nwritten, tmp, false /* already locked? */);
158 if (VBOX_FAILURE (rc)) {
159 err = -EPROTO;
160 LogFunc(("vboxCallWrite(%s) failed rc=%Vrc\n",
161 sf_i->path->String.utf8, rc));
162 goto fail;
163 }
164
165 pos += nwritten;
166 left -= nwritten;
167 buf += nwritten;
168 total_bytes_written += nwritten;
169 if (nwritten != to_write) {
170 break;
171 }
172 }
173
174#if 1 /* XXX: which way is correct? */
175 *off += total_bytes_written;
176#else
177 file->f_pos += total_bytes_written;
178#endif
179 sf_i->force_restat = 1;
180 kfree (tmp);
181 return total_bytes_written;
182
183 fail:
184 kfree (tmp);
185 return err;
186}
187
188static int
189sf_reg_open (struct inode *inode, struct file *file)
190{
191 int rc, rc_linux = 0;
192 struct sf_glob_info *sf_g = GET_GLOB_INFO (inode->i_sb);
193 struct sf_inode_info *sf_i = GET_INODE_INFO (inode);
194 struct sf_reg_info *sf_r;
195 SHFLCREATEPARMS params;
196
197 TRACE ();
198 BUG_ON (!sf_g);
199 BUG_ON (!sf_i);
200
201 sf_r = kmalloc (sizeof (*sf_r), GFP_KERNEL);
202 if (!sf_r) {
203 LogRelFunc(("could not allocate reg info\n"));
204 return -ENOMEM;
205 }
206
207 LogFunc(("open %s\n", sf_i->path->String.utf8));
208
209 params.CreateFlags = 0;
210 params.Info.cbObject = 0;
211 /* We check this afterwards to find out if the call succeeded
212 or failed, as the API does not seem to cleanly distinguish
213 error and informational messages. */
214 params.Handle = 0;
215
216 if (file->f_flags & O_CREAT) {
217 LogFunc(("O_CREAT set\n"));
218 params.CreateFlags |= SHFL_CF_ACT_CREATE_IF_NEW;
219 /* We ignore O_EXCL, as the Linux kernel seems to call create
220 beforehand itself, so O_EXCL should always fail. */
221 if (file->f_flags & O_TRUNC) {
222 LogFunc(("O_TRUNC set\n"));
223 params.CreateFlags |= ( SHFL_CF_ACT_OVERWRITE_IF_EXISTS
224 | SHFL_CF_ACCESS_WRITE);
225 }
226 else {
227 params.CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS;
228 }
229 }
230 else {
231 params.CreateFlags |= SHFL_CF_ACT_FAIL_IF_NEW;
232 if (file->f_flags & O_TRUNC) {
233 LogFunc(("O_TRUNC set\n"));
234 params.CreateFlags |= ( SHFL_CF_ACT_OVERWRITE_IF_EXISTS
235 | SHFL_CF_ACCESS_WRITE);
236 }
237 }
238
239 if (!(params.CreateFlags & SHFL_CF_ACCESS_READWRITE)) {
240 switch (file->f_flags & O_ACCMODE) {
241 case O_RDONLY:
242 params.CreateFlags |= SHFL_CF_ACCESS_READ;
243 break;
244
245 case O_WRONLY:
246 params.CreateFlags |= SHFL_CF_ACCESS_WRITE;
247 break;
248
249 case O_RDWR:
250 params.CreateFlags |= SHFL_CF_ACCESS_READWRITE;
251 break;
252
253 default:
254 BUG ();
255 }
256 }
257
258 LogFunc(("sf_reg_open: calling vboxCallCreate, file %s, flags=%d, %#x\n",
259 sf_i->path->String.utf8 , file->f_flags, params.CreateFlags));
260 rc = vboxCallCreate (&client_handle, &sf_g->map, sf_i->path, &params);
261
262 if (VBOX_FAILURE (rc)) {
263 LogFunc(("vboxCallCreate failed flags=%d,%#x rc=%Vrc\n",
264 file->f_flags, params.CreateFlags, rc));
265 kfree (sf_r);
266 return -RTErrConvertToErrno(rc);
267 }
268
269 if (SHFL_HANDLE_NIL == params.Handle) {
270 switch (params.Result) {
271 case SHFL_PATH_NOT_FOUND:
272 case SHFL_FILE_NOT_FOUND:
273 rc_linux = -ENOENT;
274 break;
275 case SHFL_FILE_EXISTS:
276 rc_linux = -EEXIST;
277 break;
278 default:
279 break;
280 }
281 }
282
283 sf_i->force_restat = 1;
284 sf_r->handle = params.Handle;
285 file->private_data = sf_r;
286 return rc_linux;
287}
288
289static int
290sf_reg_release (struct inode *inode, struct file *file)
291{
292 int rc;
293 struct sf_reg_info *sf_r;
294 struct sf_glob_info *sf_g;
295
296 TRACE ();
297 sf_g = GET_GLOB_INFO (inode->i_sb);
298 sf_r = file->private_data;
299
300 BUG_ON (!sf_g);
301 BUG_ON (!sf_r);
302
303 rc = vboxCallClose (&client_handle, &sf_g->map, sf_r->handle);
304 if (VBOX_FAILURE (rc)) {
305 LogFunc(("vboxCallClose failed rc=%Vrc\n", rc));
306 }
307
308 kfree (sf_r);
309 file->private_data = NULL;
310 return 0;
311}
312
313static struct page *
314#if LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 0)
315sf_reg_nopage (struct vm_area_struct *vma, unsigned long vaddr, int unused)
316#define SET_TYPE(t)
317#else
318sf_reg_nopage (struct vm_area_struct *vma, unsigned long vaddr, int *type)
319#define SET_TYPE(t) *type = (t)
320#endif
321{
322 struct page *page;
323 char *buf;
324 loff_t off;
325 uint32_t nread = PAGE_SIZE;
326 int err;
327 struct file *file = vma->vm_file;
328 struct inode *inode = file->f_dentry->d_inode;
329 struct sf_glob_info *sf_g = GET_GLOB_INFO (inode->i_sb);
330 struct sf_reg_info *sf_r = file->private_data;
331
332 TRACE ();
333 if (vaddr > vma->vm_end) {
334 SET_TYPE (VM_FAULT_SIGBUS);
335 return NOPAGE_SIGBUS;
336 }
337
338 page = alloc_page (GFP_HIGHUSER);
339 if (!page) {
340 LogRelFunc(("failed to allocate page\n"));
341 SET_TYPE (VM_FAULT_OOM);
342 return NOPAGE_OOM;
343 }
344
345 buf = kmap (page);
346 off = (vaddr - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
347 err = sf_reg_read_aux (__func__, sf_g, sf_r, buf, &nread, off);
348 if (err) {
349 kunmap (page);
350 put_page (page);
351 SET_TYPE (VM_FAULT_SIGBUS);
352 return NOPAGE_SIGBUS;
353 }
354
355 BUG_ON (nread > PAGE_SIZE);
356 if (!nread) {
357#if LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 0)
358 clear_user_page (page_address (page), vaddr);
359#else
360 clear_user_page (page_address (page), vaddr, page);
361#endif
362 }
363 else {
364 memset (buf + nread, 0, PAGE_SIZE - nread);
365 }
366
367 flush_dcache_page (page);
368 kunmap (page);
369 SET_TYPE (VM_FAULT_MAJOR);
370 return page;
371}
372
373static struct vm_operations_struct sf_vma_ops = {
374 .nopage = sf_reg_nopage
375};
376
377static int
378sf_reg_mmap (struct file *file, struct vm_area_struct *vma)
379{
380 TRACE ();
381 if (vma->vm_flags & VM_SHARED) {
382 LogFunc(("shared mmapping not available\n"));
383 return -EINVAL;
384 }
385
386 vma->vm_ops = &sf_vma_ops;
387 return 0;
388}
389
390struct file_operations sf_reg_fops = {
391 .read = sf_reg_read,
392 .open = sf_reg_open,
393 .write = sf_reg_write,
394 .release = sf_reg_release,
395 .mmap = sf_reg_mmap,
396#if LINUX_VERSION_CODE >= KERNEL_VERSION (2, 6, 0)
397# if LINUX_VERSION_CODE >= KERNEL_VERSION (2, 6, 23)
398 .splice_read = generic_file_splice_read,
399# else
400 .sendfile = generic_file_sendfile,
401# endif
402 .aio_read = generic_file_aio_read,
403 .aio_write = generic_file_aio_write,
404 .fsync = simple_sync_file,
405 .llseek = generic_file_llseek,
406#endif
407};
408
409
410struct inode_operations sf_reg_iops = {
411#if LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 0)
412 .revalidate = sf_inode_revalidate
413#else
414 .getattr = sf_getattr
415#endif
416};
417
418
419#if LINUX_VERSION_CODE >= KERNEL_VERSION (2, 6, 0)
420static int
421sf_readpage(struct file *file, struct page *page)
422{
423 char *buf = kmap(page);
424 struct inode *inode = file->f_dentry->d_inode;
425 struct sf_glob_info *sf_g = GET_GLOB_INFO (inode->i_sb);
426 struct sf_reg_info *sf_r = file->private_data;
427 uint32_t nread = PAGE_SIZE;
428 loff_t off = page->index << PAGE_SHIFT;
429 int ret;
430
431 TRACE ();
432
433 ret = sf_reg_read_aux (__func__, sf_g, sf_r, buf, &nread, off);
434 if (ret) {
435 kunmap (page);
436 return ret;
437 }
438 flush_dcache_page (page);
439 kunmap (page);
440 SetPageUptodate(page);
441 if (PageLocked(page))
442 unlock_page(page);
443 return 0;
444}
445
446struct address_space_operations sf_reg_aops = {
447 .readpage = sf_readpage,
448# if LINUX_VERSION_CODE >= KERNEL_VERSION (2, 6, 24)
449 .write_begin = simple_write_begin,
450 .write_end = simple_write_end,
451# else
452 .prepare_write = simple_prepare_write,
453 .commit_write = simple_commit_write,
454# endif
455};
456#endif
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette