VirtualBox

source: vbox/trunk/src/VBox/Additions/linux/sharedfolders/dirops.c@ 77492

Last change on this file since 77492 was 77492, checked in by vboxsync, 6 years ago

linux/vboxsf: Default dentry/stat TTL to 200 ms as on solaris. bugref:9172

  • Use the same stat/direntry TTL default value as we do on solaris (200 ms).
  • Changed the ttl=xxx mount option to be milliseconds rather than jiffies.
  • Force inode restat in sf_setattr() as a temp workaround for issue when TTL is non-zero (see older @todo in code).
  • Have separate dentry and inode update jiffies.
  • Reworked sf_dentry_revalidate and made it avoid restatting inodes more aggressively.
  • Extend TTL of parent dentry after successful opens and creation (does not extend to inodes, of course).
  • Stop using dentry::d_time like the rest of the file systems did around 4.9.0 (kernels back to 2.4.0 never seem to touch this from what I can tell, it was an file system internal field).
  • Since we only have one set of dentry ops, set super_block::s_d_op rather than calling d_set_d_op().
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.9 KB
Line 
1/* $Id: dirops.c 77492 2019-02-28 01:55:50Z vboxsync $ */
2/** @file
3 * vboxsf - VBox Linux Shared Folders VFS, directory inode and file operations.
4 */
5
6/*
7 * Copyright (C) 2006-2019 Oracle Corporation
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use,
13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following
16 * conditions:
17 *
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 * OTHER DEALINGS IN THE SOFTWARE.
29 */
30
31#include "vfsmod.h"
32#include <iprt/err.h>
33
34
35/**
36 * Reads or re-reads a directory.
37 *
38 * @note As suggested a couple of other places, we should probably stop
39 * reading in the whole directory on open.
40 */
41static int sf_dir_open_worker(struct sf_glob_info *sf_g, struct sf_dir_info *sf_d,
42 struct sf_inode_info *sf_i, const char *pszCaller)
43{
44 int rc;
45 int err;
46 union SfDirOpenCloseReq
47 {
48 VBOXSFCREATEREQ Create;
49 VBOXSFCLOSEREQ Close;
50 } *pReq;
51 SHFLCREATEPARMS *pCreateParms;
52
53 pReq = (union SfDirOpenCloseReq *)VbglR0PhysHeapAlloc(RT_UOFFSETOF(VBOXSFCREATEREQ, StrPath.String)
54 + sf_i->path->u16Size);
55 if (pReq) {
56 memcpy(&pReq->Create.StrPath, sf_i->path, SHFLSTRING_HEADER_SIZE + sf_i->path->u16Size);
57 pCreateParms = &pReq->Create.CreateParms;
58 } else {
59 LogRelMaxFunc(64, ("failed to allocate %zu bytes for '%s' [caller: %s]\n",
60 RT_UOFFSETOF(VBOXSFCREATEREQ, StrPath.String) + sf_i->path->u16Size,
61 sf_i->path->String.ach, pszCaller));
62 return -ENOMEM;
63 }
64
65 RT_ZERO(*pCreateParms);
66 pCreateParms->Handle = SHFL_HANDLE_NIL;
67 pCreateParms->CreateFlags = SHFL_CF_DIRECTORY
68 | SHFL_CF_ACT_OPEN_IF_EXISTS
69 | SHFL_CF_ACT_FAIL_IF_NEW
70 | SHFL_CF_ACCESS_READ;
71
72 LogFunc(("calling VbglR0SfHostReqCreate on folder %s, flags %#x [caller: %s]\n",
73 sf_i->path->String.utf8, pCreateParms->CreateFlags, pszCaller));
74 rc = VbglR0SfHostReqCreate(sf_g->map.root, &pReq->Create);
75 if (RT_SUCCESS(rc)) {
76 if (pCreateParms->Result == SHFL_FILE_EXISTS) {
77
78 /** @todo We could refresh the inode information here since SHFL_FN_CREATE
79 * returns updated object information. */
80
81 /** @todo Touch the dentries from here to the mount root since a successful
82 * open means that the whole path is valid. I believe CIFS does this. */
83
84 /** @todo Reading all entries upon opening the directory doesn't seem like
85 * a good idea. */
86 sf_dir_info_empty(sf_d);
87 err = sf_dir_read_all(sf_g, sf_i, sf_d, pCreateParms->Handle);
88 } else
89 err = -ENOENT;
90
91 AssertCompile(RTASSERT_OFFSET_OF(VBOXSFCREATEREQ, CreateParms.Handle) > sizeof(VBOXSFCLOSEREQ)); /* no aliasing issues */
92 if (pCreateParms->Handle != SHFL_HANDLE_NIL)
93 {
94 rc = VbglR0SfHostReqClose(sf_g->map.root, &pReq->Close, pCreateParms->Handle);
95 if (RT_FAILURE(rc))
96 LogFunc(("VbglR0SfHostReqCloseSimple(%s) after err=%d failed rc=%Rrc caller=%s\n",
97 sf_i->path->String.utf8, err, rc, pszCaller));
98 }
99 } else
100 err = -EPERM;
101
102 VbglR0PhysHeapFree(pReq);
103 return err;
104}
105
106/**
107 * Open a directory. Read the complete content into a buffer.
108 *
109 * @param inode inode
110 * @param file file
111 * @returns 0 on success, Linux error code otherwise
112 */
113static int sf_dir_open(struct inode *inode, struct file *file)
114{
115 int err;
116 struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
117 struct sf_dir_info *sf_d;
118 struct sf_inode_info *sf_i = GET_INODE_INFO(inode);
119
120 TRACE();
121 BUG_ON(!sf_g);
122 BUG_ON(!sf_i);
123
124 if (file->private_data) {
125 LogFunc(("called on already opened directory '%s'!\n", sf_i->path->String.ach));
126 return 0;
127 }
128
129 sf_d = sf_dir_info_alloc();
130 if (!sf_d) {
131 LogRelFunc(("could not allocate directory info for '%s'\n", sf_i->path->String.ach));
132 return -ENOMEM;
133 }
134
135 err = sf_dir_open_worker(sf_g, sf_d, sf_i, "sf_dir_open");
136 if (!err)
137 file->private_data = sf_d;
138 else
139 sf_dir_info_free(sf_d);
140
141 return err;
142}
143
144/**
145 * This is called when reference count of [file] goes to zero. Notify
146 * the host that it can free whatever is associated with this directory
147 * and deallocate our own internal buffers
148 *
149 * @param inode inode
150 * @param file file
151 * returns 0 on success, Linux error code otherwise
152 */
153static int sf_dir_release(struct inode *inode, struct file *file)
154{
155 TRACE();
156
157 if (file->private_data)
158 sf_dir_info_free(file->private_data);
159
160 return 0;
161}
162
163/**
164 * Translate RTFMODE into DT_xxx (in conjunction to rtDirType())
165 * @param fMode file mode
166 * returns d_type
167 */
168static int sf_get_d_type(RTFMODE fMode)
169{
170 int d_type;
171 switch (fMode & RTFS_TYPE_MASK) {
172 case RTFS_TYPE_FIFO:
173 d_type = DT_FIFO;
174 break;
175 case RTFS_TYPE_DEV_CHAR:
176 d_type = DT_CHR;
177 break;
178 case RTFS_TYPE_DIRECTORY:
179 d_type = DT_DIR;
180 break;
181 case RTFS_TYPE_DEV_BLOCK:
182 d_type = DT_BLK;
183 break;
184 case RTFS_TYPE_FILE:
185 d_type = DT_REG;
186 break;
187 case RTFS_TYPE_SYMLINK:
188 d_type = DT_LNK;
189 break;
190 case RTFS_TYPE_SOCKET:
191 d_type = DT_SOCK;
192 break;
193 case RTFS_TYPE_WHITEOUT:
194 d_type = DT_WHT;
195 break;
196 default:
197 d_type = DT_UNKNOWN;
198 break;
199 }
200 return d_type;
201}
202
203/**
204 * Extract element ([dir]->f_pos) from the directory [dir] into [d_name].
205 *
206 * @returns 0 for success, 1 for end reached, Linux error code otherwise.
207 */
208static int sf_getdent(struct file *dir, char d_name[NAME_MAX], int *d_type)
209{
210 loff_t cur;
211 struct sf_glob_info *sf_g;
212 struct sf_dir_info *sf_d;
213 struct sf_inode_info *sf_i;
214 struct inode *inode;
215 struct list_head *pos, *list;
216
217 TRACE();
218
219 inode = GET_F_DENTRY(dir)->d_inode;
220 sf_i = GET_INODE_INFO(inode);
221 sf_g = GET_GLOB_INFO(inode->i_sb);
222 sf_d = dir->private_data;
223
224 BUG_ON(!sf_g);
225 BUG_ON(!sf_d);
226 BUG_ON(!sf_i);
227
228 if (sf_i->force_reread) {
229 int err = sf_dir_open_worker(sf_g, sf_d, sf_i, "sf_getdent");
230 if (!err) {
231 sf_i->force_reread = 0;
232 } else {
233 if (err == -ENOENT) {
234 sf_dir_info_free(sf_d);
235 dir->private_data = NULL;
236 }
237 return err;
238 }
239 }
240
241 cur = 0;
242 list = &sf_d->info_list;
243 list_for_each(pos, list) {
244 struct sf_dir_buf *b;
245 SHFLDIRINFO *info;
246 loff_t i;
247
248 b = list_entry(pos, struct sf_dir_buf, head);
249 if (dir->f_pos >= cur + b->cEntries) {
250 cur += b->cEntries;
251 continue;
252 }
253
254 for (i = 0, info = b->buf; i < dir->f_pos - cur; ++i) {
255 size_t size;
256
257 size = offsetof(SHFLDIRINFO, name.String)
258 + info->name.u16Size;
259 info = (SHFLDIRINFO *)((uintptr_t)info + size);
260 }
261
262 *d_type = sf_get_d_type(info->Info.Attr.fMode);
263
264 return sf_nlscpy(sf_g, d_name, NAME_MAX,
265 info->name.String.utf8, info->name.u16Length);
266 }
267
268 return 1;
269}
270
271/**
272 * This is called when vfs wants to populate internal buffers with
273 * directory [dir]s contents. [opaque] is an argument to the
274 * [filldir]. [filldir] magically modifies it's argument - [opaque]
275 * and takes following additional arguments (which i in turn get from
276 * the host via sf_getdent):
277 *
278 * name : name of the entry (i must also supply it's length huh?)
279 * type : type of the entry (FILE | DIR | etc) (i ellect to use DT_UNKNOWN)
280 * pos : position/index of the entry
281 * ino : inode number of the entry (i fake those)
282 *
283 * [dir] contains:
284 * f_pos : cursor into the directory listing
285 * private_data : mean of communication with the host side
286 *
287 * Extract elements from the directory listing (incrementing f_pos
288 * along the way) and feed them to [filldir] until:
289 *
290 * a. there are no more entries (i.e. sf_getdent set done to 1)
291 * b. failure to compute fake inode number
292 * c. filldir returns an error (see comment on that)
293 */
294#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
295static int sf_dir_iterate(struct file *dir, struct dir_context *ctx)
296#else
297static int sf_dir_read(struct file *dir, void *opaque, filldir_t filldir)
298#endif
299{
300 TRACE();
301 for (;;) {
302 int err;
303 ino_t fake_ino;
304 loff_t sanity;
305 char d_name[NAME_MAX];
306 int d_type = DT_UNKNOWN;
307
308 err = sf_getdent(dir, d_name, &d_type);
309 switch (err) {
310 case 1:
311 return 0;
312
313 case 0:
314 break;
315
316 case -1:
317 default:
318 /* skip erroneous entry and proceed */
319 LogFunc(("sf_getdent error %d\n", err));
320 dir->f_pos += 1;
321#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
322 ctx->pos += 1;
323#endif
324 continue;
325 }
326
327 /* d_name now contains a valid entry name */
328
329#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
330 sanity = ctx->pos + 0xbeef;
331#else
332 sanity = dir->f_pos + 0xbeef;
333#endif
334 fake_ino = sanity;
335 if (sanity - fake_ino) {
336 LogRelFunc(("can not compute ino\n"));
337 return -EINVAL;
338 }
339#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
340 if (!dir_emit(ctx, d_name, strlen(d_name), fake_ino, d_type)) {
341 LogFunc(("dir_emit failed\n"));
342 return 0;
343 }
344#else
345 err = filldir(opaque, d_name, strlen(d_name),
346 dir->f_pos, fake_ino, d_type);
347 if (err) {
348 LogFunc(("filldir returned error %d\n", err));
349 /* Rely on the fact that filldir returns error
350 only when it runs out of space in opaque */
351 return 0;
352 }
353#endif
354
355 dir->f_pos += 1;
356#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
357 ctx->pos += 1;
358#endif
359 }
360
361 BUG();
362}
363
364struct file_operations sf_dir_fops = {
365 .open = sf_dir_open,
366#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
367 .iterate = sf_dir_iterate,
368#else
369 .readdir = sf_dir_read,
370#endif
371 .release = sf_dir_release,
372 .read = generic_read_dir
373#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
374 , .llseek = generic_file_llseek
375#endif
376};
377
378/* iops */
379
380/**
381 * This is called when vfs failed to locate dentry in the cache. The
382 * job of this function is to allocate inode and link it to dentry.
383 * [dentry] contains the name to be looked in the [parent] directory.
384 * Failure to locate the name is not a "hard" error, in this case NULL
385 * inode is added to [dentry] and vfs should proceed trying to create
386 * the entry via other means. NULL(or "positive" pointer) ought to be
387 * returned in case of success and "negative" pointer on error
388 */
389static struct dentry *sf_lookup(struct inode *parent, struct dentry *dentry
390#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
391 , unsigned int flags
392#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
393 , struct nameidata *nd
394#endif
395 )
396{
397 int err;
398 struct sf_inode_info *sf_i, *sf_new_i;
399 struct sf_glob_info *sf_g;
400 SHFLSTRING *path;
401 struct inode *inode;
402 ino_t ino;
403 SHFLFSOBJINFO fsinfo;
404
405 TRACE();
406 sf_g = GET_GLOB_INFO(parent->i_sb);
407 sf_i = GET_INODE_INFO(parent);
408
409 BUG_ON(!sf_g);
410 BUG_ON(!sf_i);
411
412 err = sf_path_from_dentry(__func__, sf_g, sf_i, dentry, &path);
413 if (err)
414 goto fail0;
415
416 /** @todo call host directly and avoid unnecessary copying here. */
417 err = sf_stat(__func__, sf_g, path, &fsinfo, 1);
418 if (err) {
419 if (err == -ENOENT) {
420 /* -ENOENT: add NULL inode to dentry so it later can be
421 created via call to create/mkdir/open */
422 kfree(path);
423 inode = NULL;
424 } else
425 goto fail1;
426 } else {
427 sf_new_i = kmalloc(sizeof(*sf_new_i), GFP_KERNEL);
428 if (!sf_new_i) {
429 LogRelFunc(("could not allocate memory for new inode info\n"));
430 err = -ENOMEM;
431 goto fail1;
432 }
433 sf_new_i->handle = SHFL_HANDLE_NIL;
434 sf_new_i->force_reread = 0;
435 RTListInit(&sf_new_i->HandleList);
436#ifdef VBOX_STRICT
437 sf_new_i->u32Magic = SF_INODE_INFO_MAGIC;
438#endif
439
440 ino = iunique(parent->i_sb, 1);
441#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
442 inode = iget_locked(parent->i_sb, ino);
443#else
444 inode = iget(parent->i_sb, ino);
445#endif
446 if (!inode) {
447 LogFunc(("iget failed\n"));
448 err = -ENOMEM; /* XXX: ??? */
449 goto fail2;
450 }
451
452 sf_new_i->path = path;
453 SET_INODE_INFO(inode, sf_new_i);
454 sf_init_inode(inode, sf_new_i, &fsinfo, sf_g);
455
456#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
457 unlock_new_inode(inode);
458#endif
459 sf_dentry_chain_increase_parent_ttl(dentry);
460 }
461
462 //sf_i->force_restat = 0; /** @todo r=bird: This looks like confusion. */
463
464 sf_dentry_set_update_jiffies(dentry, jiffies);
465#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
466 Assert(dentry->d_op == &sf_dentry_ops); /* (taken from the superblock) */
467#else
468 dentry->d_op = &sf_dentry_ops;
469#endif
470 d_add(dentry, inode);
471 return NULL;
472
473 fail2:
474 kfree(sf_new_i);
475
476 fail1:
477 kfree(path);
478
479 fail0:
480 return ERR_PTR(err);
481}
482
483/**
484 * This should allocate memory for sf_inode_info, compute a unique inode
485 * number, get an inode from vfs, initialize inode info, instantiate
486 * dentry.
487 *
488 * @param parent inode entry of the directory
489 * @param dentry directory cache entry
490 * @param path path name
491 * @param info file information
492 * @param handle handle
493 * @returns 0 on success, Linux error code otherwise
494 */
495static int sf_instantiate(struct inode *parent, struct dentry *dentry,
496 SHFLSTRING * path, PSHFLFSOBJINFO info,
497 SHFLHANDLE handle)
498{
499 int err;
500 ino_t ino;
501 struct inode *inode;
502 struct sf_inode_info *sf_new_i;
503 struct sf_glob_info *sf_g = GET_GLOB_INFO(parent->i_sb);
504
505 TRACE();
506 BUG_ON(!sf_g);
507
508 sf_new_i = kmalloc(sizeof(*sf_new_i), GFP_KERNEL);
509 if (!sf_new_i) {
510 LogRelFunc(("could not allocate inode info.\n"));
511 err = -ENOMEM;
512 goto fail0;
513 }
514
515 ino = iunique(parent->i_sb, 1);
516#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
517 inode = iget_locked(parent->i_sb, ino);
518#else
519 inode = iget(parent->i_sb, ino);
520#endif
521 if (!inode) {
522 LogFunc(("iget failed\n"));
523 err = -ENOMEM;
524 goto fail1;
525 }
526
527 sf_init_inode(inode, sf_new_i, info, sf_g);
528
529 sf_new_i->path = path;
530 RTListInit(&sf_new_i->HandleList);
531 sf_new_i->force_restat = 1;
532 sf_new_i->force_reread = 0;
533 sf_new_i->ts_up_to_date = jiffies - INT_MAX / 2;
534#ifdef VBOX_STRICT
535 sf_new_i->u32Magic = SF_INODE_INFO_MAGIC;
536#endif
537 SET_INODE_INFO(inode, sf_new_i);
538
539 d_instantiate(dentry, inode);
540
541#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
542 unlock_new_inode(inode);
543#endif
544
545 /* Store this handle if we leave the handle open. */
546 sf_new_i->handle = handle;
547 return 0;
548
549 fail1:
550 kfree(sf_new_i);
551
552 fail0:
553 return err;
554
555}
556
557/**
558 * Create a new regular file / directory.
559 *
560 * @param parent inode of the directory
561 * @param dentry directory cache entry
562 * @param mode file mode
563 * @param fDirectory true if directory, false otherwise
564 * @returns 0 on success, Linux error code otherwise
565 */
566static int sf_create_aux(struct inode *parent, struct dentry *dentry,
567 umode_t mode, int fDirectory)
568{
569 int rc, err;
570 struct sf_inode_info *sf_i = GET_INODE_INFO(parent);
571 struct sf_glob_info *sf_g = GET_GLOB_INFO(parent->i_sb);
572 SHFLSTRING *path;
573 union CreateAuxReq
574 {
575 VBOXSFCREATEREQ Create;
576 VBOXSFCLOSEREQ Close;
577 } *pReq;
578 SHFLCREATEPARMS *pCreateParms;
579
580 TRACE();
581 BUG_ON(!sf_i);
582 BUG_ON(!sf_g);
583
584 err = sf_path_from_dentry(__func__, sf_g, sf_i, dentry, &path);
585 if (err)
586 goto fail0;
587
588 /** @todo combine with sf_path_from_dentry? */
589 pReq = (union CreateAuxReq *)VbglR0PhysHeapAlloc(RT_UOFFSETOF(VBOXSFCREATEREQ, StrPath.String) + path->u16Size);
590 if (pReq) {
591 memcpy(&pReq->Create.StrPath, path, SHFLSTRING_HEADER_SIZE + path->u16Size);
592 pCreateParms = &pReq->Create.CreateParms;
593 } else {
594 err = -ENOMEM;
595 goto fail1;
596 }
597
598 RT_ZERO(*pCreateParms);
599 pCreateParms->Handle = SHFL_HANDLE_NIL;
600 pCreateParms->CreateFlags = SHFL_CF_ACT_CREATE_IF_NEW
601 | SHFL_CF_ACT_FAIL_IF_EXISTS
602 | SHFL_CF_ACCESS_READWRITE
603 | (fDirectory ? SHFL_CF_DIRECTORY : 0);
604 pCreateParms->Info.Attr.fMode = (fDirectory ? RTFS_TYPE_DIRECTORY : RTFS_TYPE_FILE)
605 | (mode & S_IRWXUGO);
606 pCreateParms->Info.Attr.enmAdditional = RTFSOBJATTRADD_NOTHING;
607
608 LogFunc(("calling VbglR0SfHostReqCreate, folder %s, flags %#x\n", path->String.ach, pCreateParms->CreateFlags));
609 rc = VbglR0SfHostReqCreate(sf_g->map.root, &pReq->Create);
610 if (RT_FAILURE(rc)) {
611 if (rc == VERR_WRITE_PROTECT) {
612 err = -EROFS;
613 goto fail2;
614 }
615 err = -EPROTO;
616 LogFunc(("(%d): SHFL_FN_CREATE(%s) failed rc=%Rrc\n",
617 fDirectory, sf_i->path->String.utf8, rc));
618 goto fail2;
619 }
620
621 if (pCreateParms->Result != SHFL_FILE_CREATED) {
622 err = -EPERM;
623 LogFunc(("(%d): could not create file %s result=%d\n",
624 fDirectory, sf_i->path->String.utf8, pCreateParms->Result));
625 goto fail2;
626 }
627
628 sf_dentry_chain_increase_parent_ttl(dentry);
629
630 err = sf_instantiate(parent, dentry, path, &pCreateParms->Info,
631 fDirectory ? SHFL_HANDLE_NIL : pCreateParms->Handle);
632 if (err) {
633 LogFunc(("(%d): could not instantiate dentry for %s err=%d\n",
634 fDirectory, sf_i->path->String.utf8, err));
635 goto fail3;
636 }
637
638 /*
639 * Don't close this handle right now. We assume that the same file is
640 * opened with sf_reg_open() and later closed with sf_reg_close(). Save
641 * the handle in between. Does not apply to directories. True?
642 */
643 if (fDirectory) {
644 AssertCompile(RTASSERT_OFFSET_OF(VBOXSFCREATEREQ, CreateParms.Handle) > sizeof(VBOXSFCLOSEREQ)); /* no aliasing issues */
645 rc = VbglR0SfHostReqClose(sf_g->map.root, &pReq->Close, pCreateParms->Handle);
646 if (RT_FAILURE(rc))
647 LogFunc(("(%d): VbglR0SfHostReqClose failed rc=%Rrc\n", fDirectory, rc));
648 }
649
650 sf_i->force_restat = 1; /**< @todo r=bird: Why?!? */
651 VbglR0PhysHeapFree(pReq);
652 return 0;
653
654 fail3:
655 rc = VbglR0SfHostReqClose(sf_g->map.root, &pReq->Close, pCreateParms->Handle);
656 if (RT_FAILURE(rc))
657 LogFunc(("(%d): VbglR0SfHostReqCloseSimple failed rc=%Rrc\n", fDirectory, rc));
658 fail2:
659 VbglR0PhysHeapFree(pReq);
660 fail1:
661 kfree(path);
662
663 fail0:
664 return err;
665}
666
667/**
668 * Create a new regular file.
669 *
670 * @param parent inode of the directory
671 * @param dentry directory cache entry
672 * @param mode file mode
673 * @param excl Possible O_EXCL...
674 * @returns 0 on success, Linux error code otherwise
675 */
676#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) || defined(DOXYGEN_RUNNING)
677static int sf_create(struct inode *parent, struct dentry *dentry, umode_t mode,
678 bool excl)
679#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
680static int sf_create(struct inode *parent, struct dentry *dentry, umode_t mode,
681 struct nameidata *nd)
682#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
683static int sf_create(struct inode *parent, struct dentry *dentry, int mode,
684 struct nameidata *nd)
685#else
686static int sf_create(struct inode *parent, struct dentry *dentry, int mode)
687#endif
688{
689/** @todo @a nd (struct nameidata) contains intent with partial open flags for
690 * 2.6.0-3.5.999. In 3.6.0 atomic_open was introduced and stuff
691 * changed (investigate)... */
692 TRACE();
693 return sf_create_aux(parent, dentry, mode, 0 /*fDirectory*/);
694}
695
696/**
697 * Create a new directory.
698 *
699 * @param parent inode of the directory
700 * @param dentry directory cache entry
701 * @param mode file mode
702 * @returns 0 on success, Linux error code otherwise
703 */
704#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
705static int sf_mkdir(struct inode *parent, struct dentry *dentry, umode_t mode)
706#else
707static int sf_mkdir(struct inode *parent, struct dentry *dentry, int mode)
708#endif
709{
710 TRACE();
711 return sf_create_aux(parent, dentry, mode, 1 /*fDirectory*/);
712}
713
714/**
715 * Remove a regular file / directory.
716 *
717 * @param parent inode of the directory
718 * @param dentry directory cache entry
719 * @param fDirectory true if directory, false otherwise
720 * @returns 0 on success, Linux error code otherwise
721 */
722static int sf_unlink_aux(struct inode *parent, struct dentry *dentry,
723 int fDirectory)
724{
725 int rc, err;
726 struct sf_glob_info *sf_g = GET_GLOB_INFO(parent->i_sb);
727 struct sf_inode_info *sf_parent_i = GET_INODE_INFO(parent);
728 SHFLSTRING *path;
729
730 TRACE();
731 BUG_ON(!sf_g);
732
733 err = sf_path_from_dentry(__func__, sf_g, sf_parent_i, dentry, &path);
734 if (!err) {
735 VBOXSFREMOVEREQ *pReq = (VBOXSFREMOVEREQ *)VbglR0PhysHeapAlloc(RT_UOFFSETOF(VBOXSFREMOVEREQ, StrPath.String)
736 + path->u16Size);
737 if (pReq) {
738 memcpy(&pReq->StrPath, path, SHFLSTRING_HEADER_SIZE + path->u16Size);
739 uint32_t fFlags = fDirectory ? SHFL_REMOVE_DIR : SHFL_REMOVE_FILE;
740 if (dentry->d_inode && ((dentry->d_inode->i_mode & S_IFLNK) == S_IFLNK))
741 fFlags |= SHFL_REMOVE_SYMLINK;
742
743 rc = VbglR0SfHostReqRemove(sf_g->map.root, pReq, fFlags);
744
745 if (dentry->d_inode) {
746 struct sf_inode_info *sf_i = GET_INODE_INFO(dentry->d_inode);
747 sf_i->force_restat = 1;
748 sf_i->force_reread = 1;
749 }
750
751 if (RT_SUCCESS(rc)) {
752 /* directory access/change time changed */
753 sf_parent_i->force_restat = 1;
754 /* directory content changed */
755 sf_parent_i->force_reread = 1;
756
757 err = 0;
758 } else if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND) {
759 LogFunc(("(%d): VbglR0SfRemove(%s) failed rc=%Rrc; calling d_drop on %p\n",
760 fDirectory, path->String.utf8, rc, dentry));
761 d_drop(dentry);
762 } else {
763 LogFunc(("(%d): VbglR0SfRemove(%s) failed rc=%Rrc\n", fDirectory, path->String.utf8, rc));
764 err = -RTErrConvertToErrno(rc);
765 }
766 VbglR0PhysHeapFree(pReq);
767 } else
768 err = -ENOMEM;
769 kfree(path);
770 }
771 return err;
772}
773
774/**
775 * Remove a regular file.
776 *
777 * @param parent inode of the directory
778 * @param dentry directory cache entry
779 * @returns 0 on success, Linux error code otherwise
780 */
781static int sf_unlink(struct inode *parent, struct dentry *dentry)
782{
783 TRACE();
784 return sf_unlink_aux(parent, dentry, 0 /*fDirectory*/);
785}
786
787/**
788 * Remove a directory.
789 *
790 * @param parent inode of the directory
791 * @param dentry directory cache entry
792 * @returns 0 on success, Linux error code otherwise
793 */
794static int sf_rmdir(struct inode *parent, struct dentry *dentry)
795{
796 TRACE();
797 return sf_unlink_aux(parent, dentry, 1 /*fDirectory*/);
798}
799
800/**
801 * Rename a regular file / directory.
802 *
803 * @param old_parent inode of the old parent directory
804 * @param old_dentry old directory cache entry
805 * @param new_parent inode of the new parent directory
806 * @param new_dentry new directory cache entry
807 * @param flags flags
808 * @returns 0 on success, Linux error code otherwise
809 */
810static int sf_rename(struct inode *old_parent, struct dentry *old_dentry,
811 struct inode *new_parent, struct dentry *new_dentry
812#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
813 , unsigned flags
814#endif
815 )
816{
817 int err = 0, rc = VINF_SUCCESS;
818 struct sf_glob_info *sf_g = GET_GLOB_INFO(old_parent->i_sb);
819
820 TRACE();
821
822#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
823 if (flags) {
824 LogFunc(("rename with flags=%x\n", flags));
825 return -EINVAL;
826 }
827#endif
828
829 if (sf_g != GET_GLOB_INFO(new_parent->i_sb)) {
830 LogFunc(("rename with different roots\n"));
831 err = -EINVAL;
832 } else {
833 struct sf_inode_info *sf_old_i = GET_INODE_INFO(old_parent);
834 struct sf_inode_info *sf_new_i = GET_INODE_INFO(new_parent);
835 /* As we save the relative path inside the inode structure, we need to change
836 this if the rename is successful. */
837 struct sf_inode_info *sf_file_i =
838 GET_INODE_INFO(old_dentry->d_inode);
839 SHFLSTRING *old_path;
840 SHFLSTRING *new_path;
841
842 BUG_ON(!sf_old_i);
843 BUG_ON(!sf_new_i);
844 BUG_ON(!sf_file_i);
845
846 old_path = sf_file_i->path;
847 err = sf_path_from_dentry(__func__, sf_g, sf_new_i,
848 new_dentry, &new_path);
849 if (err)
850 LogFunc(("failed to create new path\n"));
851 else {
852 VBOXSFRENAMEWITHSRCBUFREQ *pReq;
853 pReq = (VBOXSFRENAMEWITHSRCBUFREQ *)VbglR0PhysHeapAlloc(RT_UOFFSETOF(VBOXSFRENAMEWITHSRCBUFREQ,
854 StrDstPath.String)
855 + new_path->u16Size);
856 if (pReq) {
857 memcpy(&pReq->StrDstPath, new_path, SHFLSTRING_HEADER_SIZE + new_path->u16Size);
858 rc = VbglR0SfHostReqRenameWithSrcContig(sf_g->map.root, pReq,
859 old_path, virt_to_phys(old_path),
860 old_dentry->d_inode->i_mode & S_IFDIR ? SHFL_RENAME_DIR
861 : SHFL_RENAME_FILE | SHFL_RENAME_REPLACE_IF_EXISTS);
862 VbglR0PhysHeapFree(pReq);
863 } else
864 rc = VERR_NO_MEMORY;
865 if (RT_SUCCESS(rc)) {
866 kfree(old_path);
867 sf_new_i->force_restat = 1;
868 sf_old_i->force_restat = 1; /* XXX: needed? */
869
870 /* Set the new relative path in the inode. */
871 sf_file_i->path = new_path;
872
873 } else {
874 LogFunc(("VbglR0SfRename failed rc=%Rrc\n",
875 rc));
876 err = -RTErrConvertToErrno(rc);
877 kfree(new_path);
878 }
879 }
880 }
881 return err;
882}
883
884#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
885static int sf_symlink(struct inode *parent, struct dentry *dentry,
886 const char *symname)
887{
888 int err;
889 int rc;
890 struct sf_inode_info *sf_i;
891 struct sf_glob_info *sf_g;
892 SHFLSTRING *path, *ssymname;
893 SHFLFSOBJINFO info;
894 int symname_len = strlen(symname) + 1;
895
896 TRACE();
897 sf_g = GET_GLOB_INFO(parent->i_sb);
898 sf_i = GET_INODE_INFO(parent);
899
900 BUG_ON(!sf_g);
901 BUG_ON(!sf_i);
902
903 err = sf_path_from_dentry(__func__, sf_g, sf_i, dentry, &path);
904 if (err)
905 goto fail0;
906
907 ssymname =
908 kmalloc(offsetof(SHFLSTRING, String.utf8) + symname_len,
909 GFP_KERNEL);
910 if (!ssymname) {
911 LogRelFunc(("kmalloc failed, caller=sf_symlink\n"));
912 err = -ENOMEM;
913 goto fail1;
914 }
915
916 ssymname->u16Length = symname_len - 1;
917 ssymname->u16Size = symname_len;
918 memcpy(ssymname->String.utf8, symname, symname_len);
919
920 rc = VbglR0SfSymlink(&client_handle, &sf_g->map, path, ssymname, &info);
921 kfree(ssymname);
922
923 if (RT_FAILURE(rc)) {
924 if (rc == VERR_WRITE_PROTECT) {
925 err = -EROFS;
926 goto fail1;
927 }
928 LogFunc(("VbglR0SfSymlink(%s) failed rc=%Rrc\n",
929 sf_i->path->String.utf8, rc));
930 err = -EPROTO;
931 goto fail1;
932 }
933
934 err = sf_instantiate(parent, dentry, path, &info, SHFL_HANDLE_NIL);
935 if (err) {
936 LogFunc(("could not instantiate dentry for %s err=%d\n",
937 sf_i->path->String.utf8, err));
938 goto fail1;
939 }
940
941 sf_i->force_restat = 1;
942 return 0;
943
944 fail1:
945 kfree(path);
946 fail0:
947 return err;
948}
949#endif /* LINUX_VERSION_CODE >= 2.6.0 */
950
951struct inode_operations sf_dir_iops = {
952 .lookup = sf_lookup,
953 .create = sf_create,
954 .mkdir = sf_mkdir,
955 .rmdir = sf_rmdir,
956 .unlink = sf_unlink,
957 .rename = sf_rename,
958#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
959 .revalidate = sf_inode_revalidate
960#else
961 .getattr = sf_getattr,
962 .setattr = sf_setattr,
963 .symlink = sf_symlink
964#endif
965};
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