VirtualBox

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

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

linux/vboxsf: Workaround for kernel_read/write calls (get_user_pages fails), fixing issue with sporadic ENOEXEC from execve(). The workaround requires rtR0MemObjLinuxVirtToPage() from memobj-r0drv-linux.c. Various cleanups and adjustments. bugref:9172

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.2 KB
Line 
1/* $Id: dirops.c 77549 2019-03-04 10:00:34Z 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
32/*********************************************************************************************************************************
33* Header Files *
34*********************************************************************************************************************************/
35#include "vfsmod.h"
36#include <iprt/err.h>
37
38
39/**
40 * Open a directory (implements file_operations::open).
41 *
42 * @returns 0 on success, negative errno otherwise.
43 * @param inode inode
44 * @param file file
45 */
46static int vbsf_dir_open(struct inode *inode, struct file *file)
47{
48 struct vbsf_super_info *sf_g = VBSF_GET_SUPER_INFO(inode->i_sb);
49 struct vbsf_inode_info *sf_i = VBSF_GET_INODE_INFO(inode);
50 struct dentry *dentry = VBSF_GET_F_DENTRY(file);
51 struct vbsf_dir_info *sf_d;
52 int rc;
53
54 SFLOGFLOW(("vbsf_dir_open: inode=%p file=%p %s\n", inode, file, sf_i && sf_i->path ? sf_i->path->String.ach : NULL));
55 AssertReturn(sf_g, -EINVAL);
56 AssertReturn(sf_i, -EINVAL);
57 AssertReturn(!file->private_data, 0);
58
59 /*
60 * Allocate and initialize our directory info structure.
61 * We delay buffer allocation until vbsf_getdent is actually used.
62 */
63 sf_d = kmalloc(sizeof(*sf_d), GFP_KERNEL);
64 if (sf_d) {
65 VBOXSFCREATEREQ *pReq;
66 RT_ZERO(*sf_d);
67 sf_d->u32Magic = VBSF_DIR_INFO_MAGIC;
68 sema_init(&sf_d->Lock, 1);
69
70 /*
71 * Try open the directory.
72 */
73 pReq = (VBOXSFCREATEREQ *)VbglR0PhysHeapAlloc(RT_UOFFSETOF(VBOXSFCREATEREQ, StrPath.String) + sf_i->path->u16Size);
74 if (pReq) {
75 memcpy(&pReq->StrPath, sf_i->path, SHFLSTRING_HEADER_SIZE + sf_i->path->u16Size);
76 RT_ZERO(pReq->CreateParms);
77 pReq->CreateParms.Handle = SHFL_HANDLE_NIL;
78 pReq->CreateParms.CreateFlags = SHFL_CF_DIRECTORY
79 | SHFL_CF_ACT_OPEN_IF_EXISTS
80 | SHFL_CF_ACT_FAIL_IF_NEW
81 | SHFL_CF_ACCESS_READ;
82
83 LogFunc(("calling VbglR0SfHostReqCreate on folder %s, flags %#x\n",
84 sf_i->path->String.utf8, pReq->CreateParms.CreateFlags));
85 rc = VbglR0SfHostReqCreate(sf_g->map.root, pReq);
86 if (RT_SUCCESS(rc)) {
87 if (pReq->CreateParms.Result == SHFL_FILE_EXISTS) {
88 Assert(pReq->CreateParms.Handle != SHFL_HANDLE_NIL);
89
90 /*
91 * Update the inode info with fresh stats and increase the TTL for the
92 * dentry cache chain that got us here.
93 */
94 vbsf_update_inode(inode, sf_i, &pReq->CreateParms.Info, sf_g, true /*fLocked*/ /** @todo inode locking */);
95 vbsf_dentry_chain_increase_ttl(dentry);
96
97 sf_d->Handle.hHost = pReq->CreateParms.Handle;
98 sf_d->Handle.cRefs = 1;
99 sf_d->Handle.fFlags = VBSF_HANDLE_F_READ | VBSF_HANDLE_F_DIR | VBSF_HANDLE_F_MAGIC;
100 vbsf_handle_append(sf_i, &sf_d->Handle);
101
102 file->private_data = sf_d;
103 VbglR0PhysHeapFree(pReq);
104 SFLOGFLOW(("vbsf_dir_open(%p,%p): returns 0; hHost=%#llx\n", inode, file, sf_d->Handle.hHost));
105 return 0;
106
107 }
108 Assert(pReq->CreateParms.Handle == SHFL_HANDLE_NIL);
109
110 /*
111 * Directory does not exist, so we probably got some invalid
112 * dir cache and inode info.
113 */
114 /** @todo do more to invalidate dentry and inode here. */
115 vbsf_dentry_set_update_jiffies(dentry, jiffies + INT_MAX / 2);
116 sf_i->force_restat = true;
117 rc = -ENOENT;
118 } else
119 rc = -EPERM;
120 VbglR0PhysHeapFree(pReq);
121 } else {
122 LogRelMaxFunc(64, ("failed to allocate %zu bytes for '%s'\n",
123 RT_UOFFSETOF(VBOXSFCREATEREQ, StrPath.String) + sf_i->path->u16Size, sf_i->path->String.ach));
124 rc = -ENOMEM;
125 }
126 sf_d->u32Magic = VBSF_DIR_INFO_MAGIC_DEAD;
127 kfree(sf_d);
128 } else
129 rc = -ENOMEM;
130 SFLOGFLOW(("vbsf_dir_open(%p,%p): returns %d\n", inode, file, rc));
131 return rc;
132}
133
134
135/**
136 * This is called when reference count of [file] goes to zero. Notify
137 * the host that it can free whatever is associated with this directory
138 * and deallocate our own internal buffers
139 *
140 * @param inode inode
141 * @param file file
142 * returns 0 on success, Linux error code otherwise
143 */
144static int vbsf_dir_release(struct inode *inode, struct file *file)
145{
146 struct vbsf_dir_info *sf_d = (struct vbsf_dir_info *)file->private_data;
147
148 SFLOGFLOW(("vbsf_dir_release(%p,%p): sf_d=%p hHost=%#llx\n", inode, file, sf_d, sf_d ? sf_d->Handle.hHost : SHFL_HANDLE_NIL));
149
150 if (sf_d) {
151 struct vbsf_super_info *sf_g = VBSF_GET_SUPER_INFO(inode->i_sb);
152
153 /* Invalidate the non-handle part. */
154 sf_d->u32Magic = VBSF_DIR_INFO_MAGIC_DEAD;
155 sf_d->cEntriesLeft = 0;
156 sf_d->cbValid = 0;
157 sf_d->pEntry = NULL;
158 sf_d->fNoMoreFiles = false;
159 if (sf_d->pBuf) {
160 kfree(sf_d->pBuf);
161 sf_d->pBuf = NULL;
162 }
163
164 /* Closes the handle and frees the structure when the last reference is released. */
165 vbsf_handle_release(&sf_d->Handle, sf_g, "vbsf_dir_release");
166 }
167
168 return 0;
169}
170
171
172/**
173 * Translate RTFMODE into DT_xxx (in conjunction to rtDirType()).
174 * returns d_type
175 * @param fMode file mode
176 */
177DECLINLINE(int) vbsf_get_d_type(RTFMODE fMode)
178{
179 switch (fMode & RTFS_TYPE_MASK) {
180 case RTFS_TYPE_FIFO: return DT_FIFO;
181 case RTFS_TYPE_DEV_CHAR: return DT_CHR;
182 case RTFS_TYPE_DIRECTORY: return DT_DIR;
183 case RTFS_TYPE_DEV_BLOCK: return DT_BLK;
184 case RTFS_TYPE_FILE: return DT_REG;
185 case RTFS_TYPE_SYMLINK: return DT_LNK;
186 case RTFS_TYPE_SOCKET: return DT_SOCK;
187 case RTFS_TYPE_WHITEOUT: return DT_WHT;
188 }
189 return DT_UNKNOWN;
190}
191
192
193/**
194 * Refills the buffer with more entries.
195 *
196 * @returns 0 on success, negative errno on error,
197 */
198static int vbsf_dir_read_more(struct vbsf_dir_info *sf_d, struct vbsf_super_info *sf_g, bool fRestart)
199{
200 int rc;
201 VBOXSFLISTDIRREQ *pReq;
202
203 /*
204 * Don't call the host again if we've reached the end of the
205 * directory entries already.
206 */
207 if (sf_d->fNoMoreFiles) {
208 if (!fRestart) {
209 SFLOGFLOW(("vbsf_dir_read_more: no more files\n"));
210 return 0;
211 }
212 sf_d->fNoMoreFiles = false;
213 }
214
215 /*
216 * Make sure we've got some kind of buffers.
217 */
218 if (sf_d->pBuf) {
219 /* Likely, except for the first time. */
220 } else {
221 /** @todo make the buffer size configurable. */
222 sf_d->pBuf = (PSHFLDIRINFO)kmalloc(_64K, GFP_KERNEL);
223 if (sf_d->pBuf)
224 sf_d->cbBuf = _64K;
225 else {
226 sf_d->pBuf = (PSHFLDIRINFO)kmalloc(_4K, GFP_KERNEL);
227 if (!sf_d->pBuf) {
228 LogRelMax(10, ("vbsf_dir_read_more: Failed to allocate buffer!\n"));
229 return -ENOMEM;
230 }
231 sf_d->cbBuf = _4K;
232 }
233 }
234
235 /*
236 * Allocate a request buffer.
237 */
238 pReq = (VBOXSFLISTDIRREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq));
239 if (pReq) {
240 rc = VbglR0SfHostReqListDirContig2x(sf_g->map.root, pReq, sf_d->Handle.hHost, NULL, NIL_RTGCPHYS64,
241 fRestart ? SHFL_LIST_RESTART : SHFL_LIST_NONE,
242 sf_d->pBuf, virt_to_phys(sf_d->pBuf), sf_d->cbBuf);
243 if (RT_SUCCESS(rc)) {
244 sf_d->pEntry = sf_d->pBuf;
245 sf_d->cbValid = pReq->Parms.cb32Buffer.u.value32;
246 sf_d->cEntriesLeft = pReq->Parms.c32Entries.u.value32;
247 sf_d->fNoMoreFiles = pReq->Parms.f32More.u.value32 == 0;
248 } else {
249 sf_d->pEntry = sf_d->pBuf;
250 sf_d->cbValid = 0;
251 sf_d->cEntriesLeft = 0;
252 if (rc == VERR_NO_MORE_FILES) {
253 sf_d->fNoMoreFiles = true;
254 rc = 0;
255 } else {
256 /* In theory we could end up here with a buffer overflow, but
257 with a 4KB minimum buffer size that's very unlikely with the
258 typical filename length of today's file systems (2019). */
259 LogRelMax(16, ("vbsf_dir_read_more: VbglR0SfHostReqListDirContig2x -> %Rrc\n", rc));
260 rc = -EPROTO;
261 }
262 }
263 VbglR0PhysHeapFree(pReq);
264 } else
265 rc = -ENOMEM;
266 SFLOGFLOW(("vbsf_dir_read_more: returns %d; cbValid=%#x cEntriesLeft=%#x fNoMoreFiles=%d\n",
267 rc, sf_d->cbValid, sf_d->cEntriesLeft, sf_d->fNoMoreFiles));
268 return rc;
269}
270
271/**
272 * Helper function for when we need to convert the name, avoids wasting stack in
273 * the UTF-8 code path.
274 */
275DECL_NO_INLINE(static, bool) vbsf_dir_emit_nls(
276# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
277 struct dir_context *ctx,
278# else
279 void *opaque, filldir_t filldir, loff_t offPos,
280# endif
281 const char *pszSrcName, uint16_t cchSrcName, ino_t d_ino, int d_type,
282 struct vbsf_super_info *sf_g)
283{
284 char szDstName[NAME_MAX];
285 int rc = vbsf_nlscpy(sf_g, szDstName, sizeof(szDstName), pszSrcName, cchSrcName + 1);
286 if (rc == 0) {
287#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
288 return dir_emit(ctx, szDstName, strlen(szDstName), d_ino, d_type);
289#else
290 return filldir(opaque, szDstName, strlen(szDstName), offPos, d_ino, d_type) == 0;
291#endif
292 }
293
294 /* Assuming this is a buffer overflow issue, just silently skip it. */
295 SFLOGFLOW(("vbsf_dir_emit_nls: vbsf_nlscopy failed with %d for '%s'\n", rc, pszSrcName));
296 return true;
297}
298
299
300/**
301 * This is called when vfs wants to populate internal buffers with
302 * directory [dir]s contents. [opaque] is an argument to the
303 * [filldir]. [filldir] magically modifies it's argument - [opaque]
304 * and takes following additional arguments (which i in turn get from
305 * the host via vbsf_getdent):
306 *
307 * name : name of the entry (i must also supply it's length huh?)
308 * type : type of the entry (FILE | DIR | etc) (i ellect to use DT_UNKNOWN)
309 * pos : position/index of the entry
310 * ino : inode number of the entry (i fake those)
311 *
312 * [dir] contains:
313 * f_pos : cursor into the directory listing
314 * private_data : mean of communication with the host side
315 *
316 * Extract elements from the directory listing (incrementing f_pos
317 * along the way) and feed them to [filldir] until:
318 *
319 * a. there are no more entries (i.e. vbsf_getdent set done to 1)
320 * b. failure to compute fake inode number
321 * c. filldir returns an error (see comment on that)
322 */
323#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
324static int vbsf_dir_iterate(struct file *dir, struct dir_context *ctx)
325#else
326static int vbsf_dir_read(struct file *dir, void *opaque, filldir_t filldir)
327#endif
328{
329#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
330 loff_t offPos = ctx->pos;
331#else
332 loff_t offPos = dir->f_pos;
333#endif
334 struct vbsf_dir_info *sf_d = (struct vbsf_dir_info *)dir->private_data;
335 struct vbsf_super_info *sf_g = VBSF_GET_SUPER_INFO(VBSF_GET_F_DENTRY(dir)->d_sb);
336 int rc;
337
338 /*
339 * Lock the directory info structures.
340 */
341 if (RT_LIKELY(down_interruptible(&sf_d->Lock) == 0)) {
342 /* likely */
343 } else
344 return -ERESTARTSYS;
345
346 /*
347 * Any seek performed in the mean time?
348 */
349 if (offPos == sf_d->offPos) {
350 /* likely */
351 } else {
352 /* Restart the search if iPos is lower than the current buffer position. */
353 loff_t offCurEntry = sf_d->offPos;
354 if (offPos < offCurEntry) {
355 rc = vbsf_dir_read_more(sf_d, sf_g, true /*fRestart*/);
356 if (rc == 0)
357 offCurEntry = 0;
358 else {
359 up(&sf_d->Lock);
360 return rc;
361 }
362 }
363
364 /* Skip ahead to offPos. */
365 while (offCurEntry < offPos) {
366 uint32_t cEntriesLeft = sf_d->cEntriesLeft;
367 if ((uint64_t)(offPos - offCurEntry) >= cEntriesLeft) {
368 /* Skip the current buffer and read the next: */
369 offCurEntry += cEntriesLeft;
370 sf_d->offPos = offCurEntry;
371 sf_d->cEntriesLeft = 0;
372 rc = vbsf_dir_read_more(sf_d, sf_g, false /*fRestart*/);
373 if (rc != 0 || sf_d->cEntriesLeft == 0) {
374 up(&sf_d->Lock);
375 return rc;
376 }
377 } else {
378 do
379 {
380 PSHFLDIRINFO pEntry = sf_d->pEntry;
381 pEntry = (PSHFLDIRINFO)&pEntry->name.String.utf8[pEntry->name.u16Length];
382 AssertLogRelBreakStmt( cEntriesLeft == 1
383 || (uintptr_t)pEntry - (uintptr_t)sf_d->pBuf
384 <= sf_d->cbValid - RT_UOFFSETOF(SHFLDIRINFO, name.String),
385 sf_d->cEntriesLeft = 0);
386 sf_d->cEntriesLeft = --cEntriesLeft;
387 sf_d->offPos = ++offCurEntry;
388 } while (offPos < sf_d->offPos);
389 }
390 }
391 }
392
393 /*
394 * Handle '.' and '..' specially so we get the inode numbers right.
395 * We'll skip any '.' or '..' returned by the host (included in pos,
396 * however, to simplify the above skipping code).
397 */
398 if (offPos < 2) {
399#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
400 if (offPos == 0) {
401 if (dir_emit_dot(dir, ctx))
402 dir->f_pos = ctx->pos = sf_d->offPos = offPos = 1;
403 else {
404 up(&sf_d->Lock);
405 return 0;
406 }
407 }
408 if (offPos == 1) {
409 if (dir_emit_dotdot(dir, ctx))
410 dir->f_pos = ctx->pos = sf_d->offPos = offPos = 2;
411 else {
412 up(&sf_d->Lock);
413 return 0;
414 }
415 }
416#else
417 if (offPos == 0) {
418 rc = filldir(opaque, ".", 1, 0, VBSF_GET_F_DENTRY(dir)->d_inode->i_ino, DT_DIR);
419 if (!rc)
420 dir->f_pos = sf_d->offPos = offPos = 1;
421 else {
422 up(&sf_d->Lock);
423 return 0;
424 }
425 }
426 if (offPos == 1) {
427# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 5)
428 rc = filldir(opaque, "..", 2, 1, parent_ino(VBSF_GET_F_DENTRY(dir)), DT_DIR);
429# else
430 rc = filldir(opaque, "..", 2, 1, VBSF_GET_F_DENTRY(dir)->d_parent->d_inode->i_ino, DT_DIR);
431# endif
432 if (!rc)
433 dir->f_pos = sf_d->offPos = offPos = 2;
434 else {
435 up(&sf_d->Lock);
436 return 0;
437 }
438 }
439#endif
440 }
441
442 /*
443 * Produce stuff.
444 */
445 Assert(offPos == sf_d->offPos);
446 for (;;) {
447 PSHFLDIRINFO pBuf;
448 PSHFLDIRINFO pEntry;
449
450 /*
451 * Do we need to read more?
452 */
453 uint32_t cbValid = sf_d->cbValid;
454 uint32_t cEntriesLeft = sf_d->cEntriesLeft;
455 if (!cEntriesLeft) {
456 rc = vbsf_dir_read_more(sf_d, sf_g, false /*fRestart*/);
457 if (rc == 0) {
458 cEntriesLeft = sf_d->cEntriesLeft;
459 if (!cEntriesLeft) {
460 up(&sf_d->Lock);
461 return 0;
462 }
463 cbValid = sf_d->cbValid;
464 } else {
465 up(&sf_d->Lock);
466 return rc;
467 }
468 }
469
470 /*
471 * Feed entries to the caller.
472 */
473 pBuf = sf_d->pBuf;
474 pEntry = sf_d->pEntry;
475 do {
476 /*
477 * Validate the entry in case the host is messing with us.
478 * We're ASSUMING the host gives us a zero terminated string (UTF-8) here.
479 */
480 uintptr_t const offEntryInBuf = (uintptr_t)pEntry - (uintptr_t)pBuf;
481 uint16_t cbSrcName;
482 uint16_t cchSrcName;
483 AssertLogRelMsgBreak(offEntryInBuf + RT_UOFFSETOF(SHFLDIRINFO, name.String) <= cbValid,
484 ("%#llx + %#x vs %#x\n", offEntryInBuf, RT_UOFFSETOF(SHFLDIRINFO, name.String), cbValid));
485 cbSrcName = pEntry->name.u16Size;
486 cchSrcName = pEntry->name.u16Length;
487 AssertLogRelBreak(offEntryInBuf + RT_UOFFSETOF(SHFLDIRINFO, name.String) + cbSrcName <= cbValid);
488 AssertLogRelBreak(cchSrcName < cbSrcName);
489 AssertLogRelBreak(pEntry->name.String.ach[cchSrcName] == '\0');
490
491 /*
492 * Filter out '.' and '..' entires.
493 */
494 if ( cchSrcName > 2
495 || pEntry->name.String.ach[0] != '.'
496 || ( cchSrcName == 2
497 && pEntry->name.String.ach[1] != '.')) {
498 int const d_type = vbsf_get_d_type(pEntry->Info.Attr.fMode);
499 ino_t const d_ino = (ino_t)offPos + 0xbeef; /* very fake */
500 bool fContinue;
501 if (sf_g->fNlsIsUtf8) {
502#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
503 fContinue = dir_emit(ctx, pEntry->name.String.ach, cchSrcName, d_ino, d_type);
504#else
505 fContinue = filldir(opaque, pEntry->name.String.ach, cchSrcName, offPos, d_ino, d_type) == 0;
506#endif
507 } else {
508#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
509 fContinue = vbsf_dir_emit_nls(ctx, pEntry->name.String.ach, cchSrcName, d_ino, d_type, sf_g);
510#else
511 fContinue = vbsf_dir_emit_nls(opaque, filldir, offPos, pEntry->name.String.ach, cchSrcName,
512 d_ino, d_type, sf_g);
513#endif
514 }
515 if (fContinue) {
516 /* likely */
517 } else {
518 sf_d->cEntriesLeft = cEntriesLeft;
519 sf_d->pEntry = pEntry;
520 sf_d->offPos = offPos;
521 up(&sf_d->Lock);
522 return 0;
523 }
524 }
525
526 /*
527 * Advance to the next entry.
528 */
529 pEntry = (PSHFLDIRINFO)((uintptr_t)pEntry + RT_UOFFSETOF(SHFLDIRINFO, name.String) + cbSrcName);
530 offPos += 1;
531 dir->f_pos = offPos;
532#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
533 ctx->pos = offPos;
534#endif
535 cEntriesLeft -= 1;
536 } while (cEntriesLeft > 0);
537
538 /* Done with all available entries. */
539 sf_d->offPos = offPos + cEntriesLeft;
540 sf_d->pEntry = pBuf;
541 sf_d->cEntriesLeft = 0;
542 }
543}
544
545/**
546 * Directory file operations.
547 */
548struct file_operations vbsf_dir_fops = {
549 .open = vbsf_dir_open,
550#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
551 .iterate_shared = vbsf_dir_iterate,
552#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
553 .iterate = vbsf_dir_iterate,
554#else
555 .readdir = vbsf_dir_read,
556#endif
557 .release = vbsf_dir_release,
558 .read = generic_read_dir
559#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
560 , .llseek = generic_file_llseek
561#endif
562};
563
564/* iops */
565
566/**
567 * Worker for vbsf_inode_lookup() and vbsf_inode_instantiate().
568 */
569static struct inode *vbsf_create_inode(struct inode *parent, struct dentry *dentry, PSHFLSTRING path,
570 PSHFLFSOBJINFO pObjInfo, struct vbsf_super_info *sf_g, bool fInstantiate)
571{
572 /*
573 * Allocate memory for our additional inode info and create an inode.
574 */
575 struct vbsf_inode_info *sf_new_i = (struct vbsf_inode_info *)kmalloc(sizeof(*sf_new_i), GFP_KERNEL);
576 if (sf_new_i) {
577 ino_t iNodeNo = iunique(parent->i_sb, 16);
578#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
579 struct inode *pInode = iget_locked(parent->i_sb, iNodeNo);
580#else
581 struct inode *pInode = iget(parent->i_sb, iNodeNo);
582#endif
583 if (pInode) {
584 /*
585 * Initialize the two structures.
586 */
587#ifdef VBOX_STRICT
588 sf_new_i->u32Magic = SF_INODE_INFO_MAGIC;
589#endif
590 sf_new_i->path = path;
591 sf_new_i->force_restat = false;
592 sf_new_i->ts_up_to_date = jiffies;
593 RTListInit(&sf_new_i->HandleList);
594 sf_new_i->handle = SHFL_HANDLE_NIL;
595
596 VBSF_SET_INODE_INFO(pInode, sf_new_i);
597 vbsf_init_inode(pInode, sf_new_i, pObjInfo, sf_g);
598
599 /*
600 * Before we unlock the new inode, we may need to call d_instantiate.
601 */
602 if (fInstantiate)
603 d_instantiate(dentry, pInode);
604#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
605 unlock_new_inode(pInode);
606#endif
607 return pInode;
608
609 }
610 LogFunc(("iget failed\n"));
611 kfree(sf_new_i);
612 } else
613 LogRelFunc(("could not allocate memory for new inode info\n"));
614 return NULL;
615}
616
617/**
618 * This is called when vfs failed to locate dentry in the cache. The
619 * job of this function is to allocate inode and link it to dentry.
620 * [dentry] contains the name to be looked in the [parent] directory.
621 * Failure to locate the name is not a "hard" error, in this case NULL
622 * inode is added to [dentry] and vfs should proceed trying to create
623 * the entry via other means. NULL(or "positive" pointer) ought to be
624 * returned in case of success and "negative" pointer on error
625 */
626static struct dentry *vbsf_inode_lookup(struct inode *parent, struct dentry *dentry
627#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
628 , unsigned int flags
629#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
630 , struct nameidata *nd
631#endif
632 )
633{
634 struct vbsf_super_info *sf_g = VBSF_GET_SUPER_INFO(parent->i_sb);
635 struct vbsf_inode_info *sf_i = VBSF_GET_INODE_INFO(parent);
636 SHFLSTRING *path;
637 struct dentry *dret;
638 int rc;
639
640#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
641 SFLOGFLOW(("vbsf_inode_lookup: parent=%p dentry=%p flags=%#x\n", parent, dentry, flags));
642#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
643 SFLOGFLOW(("vbsf_inode_lookup: parent=%p dentry=%p nd=%p{.flags=%#x}\n", parent, dentry, nd, nd ? nd->flags : 0));
644#else
645 SFLOGFLOW(("vbsf_inode_lookup: parent=%p dentry=%p\n", parent, dentry));
646#endif
647
648 Assert(sf_g);
649 Assert(sf_i && sf_i->u32Magic == SF_INODE_INFO_MAGIC);
650
651 /*
652 * Build the path. We'll associate the path with dret's inode on success.
653 */
654 rc = vbsf_path_from_dentry(__func__, sf_g, sf_i, dentry, &path);
655 if (rc == 0) {
656 /*
657 * Do a lookup on the host side.
658 */
659 VBOXSFCREATEREQ *pReq = (VBOXSFCREATEREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq) + path->u16Size);
660 if (pReq) {
661 struct inode *pInode = NULL;
662
663 RT_ZERO(*pReq);
664 memcpy(&pReq->StrPath, path, SHFLSTRING_HEADER_SIZE + path->u16Size);
665 pReq->CreateParms.Handle = SHFL_HANDLE_NIL;
666 pReq->CreateParms.CreateFlags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW;
667
668 LogFunc(("Calling VbglR0SfHostReqCreate on %s\n", path->String.utf8));
669 rc = VbglR0SfHostReqCreate(sf_g->map.root, pReq);
670 if (RT_SUCCESS(rc)) {
671 if (pReq->CreateParms.Result == SHFL_FILE_EXISTS) {
672 /*
673 * Create an inode for the result. Since this also confirms
674 * the existence of all parent dentries, we increase their TTL.
675 */
676 pInode = vbsf_create_inode(parent, dentry, path, &pReq->CreateParms.Info, sf_g, false /*fInstantiate*/);
677 if (rc == 0) {
678 path = NULL; /* given to the inode */
679 dret = dentry;
680 } else
681 dret = (struct dentry *)ERR_PTR(-ENOMEM);
682 vbsf_dentry_chain_increase_parent_ttl(dentry);
683 } else if ( pReq->CreateParms.Result == SHFL_FILE_NOT_FOUND
684 || pReq->CreateParms.Result == SHFL_PATH_NOT_FOUND /*this probably should happen*/) {
685 dret = dentry;
686 } else {
687 AssertMsgFailed(("%d\n", pReq->CreateParms.Result));
688 dret = (struct dentry *)ERR_PTR(-EPROTO);
689 }
690 } else if (rc == VERR_INVALID_NAME) {
691 dret = dentry; /* this can happen for names like 'foo*' on a Windows host */
692 } else {
693 LogFunc(("VbglR0SfHostReqCreate failed on %s: %Rrc\n", path->String.utf8, rc));
694 dret = (struct dentry *)ERR_PTR(-EPROTO);
695 }
696 VbglR0PhysHeapFree(pReq);
697
698 /*
699 * When dret is set to dentry we got something to insert,
700 * though it may be negative (pInode == NULL).
701 */
702 if (dret == dentry) {
703 vbsf_dentry_set_update_jiffies(dentry, jiffies);
704#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
705 Assert(dentry->d_op == &vbsf_dentry_ops); /* (taken from the superblock) */
706#else
707 dentry->d_op = &vbsf_dentry_ops;
708#endif
709 d_add(dentry, pInode);
710 dret = NULL;
711 }
712 } else
713 dret = (struct dentry *)ERR_PTR(-ENOMEM);
714 if (path)
715 kfree(path);
716 } else
717 dret = (struct dentry *)ERR_PTR(rc);
718 return dret;
719}
720
721/**
722 * This should allocate memory for vbsf_inode_info, compute a unique inode
723 * number, get an inode from vfs, initialize inode info, instantiate
724 * dentry.
725 *
726 * @param parent inode entry of the directory
727 * @param dentry directory cache entry
728 * @param path path name. Consumed on success.
729 * @param info file information
730 * @param handle handle
731 * @returns 0 on success, Linux error code otherwise
732 */
733static int vbsf_inode_instantiate(struct inode *parent, struct dentry *dentry, PSHFLSTRING path,
734 PSHFLFSOBJINFO info, SHFLHANDLE handle)
735{
736 struct vbsf_super_info *sf_g = VBSF_GET_SUPER_INFO(parent->i_sb);
737 struct inode *pInode = vbsf_create_inode(parent, dentry, path, info, sf_g, true /*fInstantiate*/);
738 if (pInode) {
739 /* Store this handle if we leave the handle open. */
740 struct vbsf_inode_info *sf_new_i = VBSF_GET_INODE_INFO(pInode);
741 sf_new_i->handle = handle;
742 return 0;
743 }
744 return -ENOMEM;
745}
746
747/**
748 * Create a new regular file / directory.
749 *
750 * @param parent inode of the directory
751 * @param dentry directory cache entry
752 * @param mode file mode
753 * @param fDirectory true if directory, false otherwise
754 * @returns 0 on success, Linux error code otherwise
755 */
756static int vbsf_create_worker(struct inode *parent, struct dentry *dentry, umode_t mode, int fDirectory)
757{
758 int rc, err;
759 struct vbsf_inode_info *sf_parent_i = VBSF_GET_INODE_INFO(parent);
760 struct vbsf_super_info *sf_g = VBSF_GET_SUPER_INFO(parent->i_sb);
761 SHFLSTRING *path;
762 union CreateAuxReq
763 {
764 VBOXSFCREATEREQ Create;
765 VBOXSFCLOSEREQ Close;
766 } *pReq;
767
768 TRACE();
769 BUG_ON(!sf_parent_i);
770 BUG_ON(!sf_g);
771
772 err = vbsf_path_from_dentry(__func__, sf_g, sf_parent_i, dentry, &path);
773 if (err)
774 goto fail0;
775
776 /** @todo combine with vbsf_path_from_dentry? */
777 pReq = (union CreateAuxReq *)VbglR0PhysHeapAlloc(RT_UOFFSETOF(VBOXSFCREATEREQ, StrPath.String) + path->u16Size);
778 if (pReq) {
779 memcpy(&pReq->Create.StrPath, path, SHFLSTRING_HEADER_SIZE + path->u16Size);
780 } else {
781 err = -ENOMEM;
782 goto fail1;
783 }
784
785 RT_ZERO(pReq->Create.CreateParms);
786 pReq->Create.CreateParms.Handle = SHFL_HANDLE_NIL;
787 pReq->Create.CreateParms.CreateFlags = SHFL_CF_ACT_CREATE_IF_NEW
788 | SHFL_CF_ACT_FAIL_IF_EXISTS
789 | SHFL_CF_ACCESS_READWRITE
790 | (fDirectory ? SHFL_CF_DIRECTORY : 0);
791 pReq->Create.CreateParms.Info.Attr.fMode = (fDirectory ? RTFS_TYPE_DIRECTORY : RTFS_TYPE_FILE)
792 | sf_access_permissions_to_vbox(mode);
793 pReq->Create.CreateParms.Info.Attr.enmAdditional = RTFSOBJATTRADD_NOTHING;
794
795 LogFunc(("calling VbglR0SfHostReqCreate, folder %s, flags %#x\n", path->String.ach, pReq->Create.CreateParms.CreateFlags));
796 rc = VbglR0SfHostReqCreate(sf_g->map.root, &pReq->Create);
797 if (RT_FAILURE(rc)) {
798 err = -RTErrConvertToErrno(rc);
799 LogFunc(("(%d): SHFL_FN_CREATE(%s) failed rc=%Rrc err=%d\n", fDirectory, sf_parent_i->path->String.utf8, rc, err));
800 goto fail2;
801 }
802
803 if (pReq->Create.CreateParms.Result != SHFL_FILE_CREATED) {
804 err = -EPERM;
805 LogFunc(("(%d): could not create file %s result=%d\n",
806 fDirectory, sf_parent_i->path->String.utf8, pReq->Create.CreateParms.Result));
807 goto fail2;
808 }
809
810 vbsf_dentry_chain_increase_parent_ttl(dentry);
811
812 err = vbsf_inode_instantiate(parent, dentry, path, &pReq->Create.CreateParms.Info,
813 fDirectory ? SHFL_HANDLE_NIL : pReq->Create.CreateParms.Handle);
814 if (err) {
815 LogFunc(("(%d): could not instantiate dentry for %s err=%d\n", fDirectory, path->String.utf8, err));
816 goto fail3;
817 }
818
819 /*
820 * Don't close this handle right now. We assume that the same file is
821 * opened with vbsf_reg_open() and later closed with sf_reg_close(). Save
822 * the handle in between. Does not apply to directories. True?
823 */
824 if (fDirectory) {
825 AssertCompile(RTASSERT_OFFSET_OF(VBOXSFCREATEREQ, CreateParms.Handle) > sizeof(VBOXSFCLOSEREQ)); /* no aliasing issues */
826 rc = VbglR0SfHostReqClose(sf_g->map.root, &pReq->Close, pReq->Create.CreateParms.Handle);
827 if (RT_FAILURE(rc))
828 LogFunc(("(%d): VbglR0SfHostReqClose failed rc=%Rrc\n", fDirectory, rc));
829 }
830
831 sf_parent_i->force_restat = 1;
832 VbglR0PhysHeapFree(pReq);
833 return 0;
834
835 fail3:
836 rc = VbglR0SfHostReqClose(sf_g->map.root, &pReq->Close, pReq->Create.CreateParms.Handle);
837 if (RT_FAILURE(rc))
838 LogFunc(("(%d): VbglR0SfHostReqCloseSimple failed rc=%Rrc\n", fDirectory, rc));
839 fail2:
840 VbglR0PhysHeapFree(pReq);
841 fail1:
842 kfree(path);
843
844 fail0:
845 return err;
846}
847
848/**
849 * Create a new regular file.
850 *
851 * @param parent inode of the directory
852 * @param dentry directory cache entry
853 * @param mode file mode
854 * @param excl Possible O_EXCL...
855 * @returns 0 on success, Linux error code otherwise
856 */
857#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) || defined(DOXYGEN_RUNNING)
858static int vbsf_inode_create(struct inode *parent, struct dentry *dentry, umode_t mode, bool excl)
859#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
860static int vbsf_inode_create(struct inode *parent, struct dentry *dentry, umode_t mode, struct nameidata *nd)
861#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
862static int vbsf_inode_create(struct inode *parent, struct dentry *dentry, int mode, struct nameidata *nd)
863#else
864static int vbsf_inode_create(struct inode *parent, struct dentry *dentry, int mode)
865#endif
866{
867/** @todo @a nd (struct nameidata) contains intent with partial open flags for
868 * 2.6.0-3.5.999. In 3.6.0 atomic_open was introduced and stuff
869 * changed (investigate)... */
870 TRACE();
871 return vbsf_create_worker(parent, dentry, mode, 0 /*fDirectory*/);
872}
873
874/**
875 * Create a new directory.
876 *
877 * @param parent inode of the directory
878 * @param dentry directory cache entry
879 * @param mode file mode
880 * @returns 0 on success, Linux error code otherwise
881 */
882#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
883static int vbsf_inode_mkdir(struct inode *parent, struct dentry *dentry, umode_t mode)
884#else
885static int vbsf_inode_mkdir(struct inode *parent, struct dentry *dentry, int mode)
886#endif
887{
888 TRACE();
889 return vbsf_create_worker(parent, dentry, mode, 1 /*fDirectory*/);
890}
891
892/**
893 * Remove a regular file / directory.
894 *
895 * @param parent inode of the directory
896 * @param dentry directory cache entry
897 * @param fDirectory true if directory, false otherwise
898 * @returns 0 on success, Linux error code otherwise
899 */
900static int vbsf_unlink_worker(struct inode *parent, struct dentry *dentry, int fDirectory)
901{
902 int rc, err;
903 struct vbsf_super_info *sf_g = VBSF_GET_SUPER_INFO(parent->i_sb);
904 struct vbsf_inode_info *sf_parent_i = VBSF_GET_INODE_INFO(parent);
905 SHFLSTRING *path;
906
907 TRACE();
908 BUG_ON(!sf_g);
909
910 err = vbsf_path_from_dentry(__func__, sf_g, sf_parent_i, dentry, &path);
911 if (!err) {
912 VBOXSFREMOVEREQ *pReq = (VBOXSFREMOVEREQ *)VbglR0PhysHeapAlloc(RT_UOFFSETOF(VBOXSFREMOVEREQ, StrPath.String)
913 + path->u16Size);
914 if (pReq) {
915 memcpy(&pReq->StrPath, path, SHFLSTRING_HEADER_SIZE + path->u16Size);
916 uint32_t fFlags = fDirectory ? SHFL_REMOVE_DIR : SHFL_REMOVE_FILE;
917 if (dentry->d_inode && ((dentry->d_inode->i_mode & S_IFLNK) == S_IFLNK))
918 fFlags |= SHFL_REMOVE_SYMLINK;
919
920 rc = VbglR0SfHostReqRemove(sf_g->map.root, pReq, fFlags);
921
922 if (dentry->d_inode) {
923 struct vbsf_inode_info *sf_i = VBSF_GET_INODE_INFO(dentry->d_inode);
924 sf_i->force_restat = true;
925 }
926
927 if (RT_SUCCESS(rc)) {
928 sf_parent_i->force_restat = true; /* directory access/change time changed */
929 err = 0;
930 } else if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND) {
931 LogFunc(("(%d): VbglR0SfRemove(%s) failed rc=%Rrc; calling d_drop on %p\n",
932 fDirectory, path->String.utf8, rc, dentry));
933 d_drop(dentry);
934 } else {
935 LogFunc(("(%d): VbglR0SfRemove(%s) failed rc=%Rrc\n", fDirectory, path->String.utf8, rc));
936 err = -RTErrConvertToErrno(rc);
937 }
938 VbglR0PhysHeapFree(pReq);
939 } else
940 err = -ENOMEM;
941 kfree(path);
942 }
943 return err;
944}
945
946/**
947 * Remove a regular file.
948 *
949 * @param parent inode of the directory
950 * @param dentry directory cache entry
951 * @returns 0 on success, Linux error code otherwise
952 */
953static int vbsf_inode_unlink(struct inode *parent, struct dentry *dentry)
954{
955 TRACE();
956 return vbsf_unlink_worker(parent, dentry, false /*fDirectory*/);
957}
958
959/**
960 * Remove a directory.
961 *
962 * @param parent inode of the directory
963 * @param dentry directory cache entry
964 * @returns 0 on success, Linux error code otherwise
965 */
966static int vbsf_inode_rmdir(struct inode *parent, struct dentry *dentry)
967{
968 TRACE();
969 return vbsf_unlink_worker(parent, dentry, true /*fDirectory*/);
970}
971
972/**
973 * Rename a regular file / directory.
974 *
975 * @param old_parent inode of the old parent directory
976 * @param old_dentry old directory cache entry
977 * @param new_parent inode of the new parent directory
978 * @param new_dentry new directory cache entry
979 * @param flags flags
980 * @returns 0 on success, Linux error code otherwise
981 */
982static int vbsf_inode_rename(struct inode *old_parent, struct dentry *old_dentry,
983 struct inode *new_parent, struct dentry *new_dentry
984#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
985 , unsigned flags
986#endif
987 )
988{
989 int err = 0, rc = VINF_SUCCESS;
990 struct vbsf_super_info *sf_g = VBSF_GET_SUPER_INFO(old_parent->i_sb);
991
992 TRACE();
993
994#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
995 if (flags) {
996 LogFunc(("rename with flags=%x\n", flags));
997 return -EINVAL;
998 }
999#endif
1000
1001 if (sf_g != VBSF_GET_SUPER_INFO(new_parent->i_sb)) {
1002 LogFunc(("rename with different roots\n"));
1003 err = -EINVAL;
1004 } else {
1005 struct vbsf_inode_info *sf_old_i = VBSF_GET_INODE_INFO(old_parent);
1006 struct vbsf_inode_info *sf_new_i = VBSF_GET_INODE_INFO(new_parent);
1007 /* As we save the relative path inside the inode structure, we need to change
1008 this if the rename is successful. */
1009 struct vbsf_inode_info *sf_file_i = VBSF_GET_INODE_INFO(old_dentry->d_inode);
1010 SHFLSTRING *old_path;
1011 SHFLSTRING *new_path;
1012
1013 BUG_ON(!sf_old_i);
1014 BUG_ON(!sf_new_i);
1015 BUG_ON(!sf_file_i);
1016
1017 old_path = sf_file_i->path;
1018 err = vbsf_path_from_dentry(__func__, sf_g, sf_new_i, new_dentry, &new_path);
1019 if (err)
1020 LogFunc(("failed to create new path\n"));
1021 else {
1022 VBOXSFRENAMEWITHSRCBUFREQ *pReq;
1023 pReq = (VBOXSFRENAMEWITHSRCBUFREQ *)VbglR0PhysHeapAlloc(RT_UOFFSETOF(VBOXSFRENAMEWITHSRCBUFREQ, StrDstPath.String)
1024 + new_path->u16Size);
1025 if (pReq) {
1026 memcpy(&pReq->StrDstPath, new_path, SHFLSTRING_HEADER_SIZE + new_path->u16Size);
1027 rc = VbglR0SfHostReqRenameWithSrcContig(sf_g->map.root, pReq,
1028 old_path, virt_to_phys(old_path),
1029 old_dentry->d_inode->i_mode & S_IFDIR ? SHFL_RENAME_DIR
1030 : SHFL_RENAME_FILE | SHFL_RENAME_REPLACE_IF_EXISTS);
1031 VbglR0PhysHeapFree(pReq);
1032 } else
1033 rc = VERR_NO_MEMORY;
1034 if (RT_SUCCESS(rc)) {
1035 kfree(old_path);
1036 sf_new_i->force_restat = 1;
1037 sf_old_i->force_restat = 1; /* XXX: needed? */
1038
1039 /* Set the new relative path in the inode. */
1040 sf_file_i->path = new_path;
1041 } else {
1042 LogFunc(("VbglR0SfRename failed rc=%Rrc\n",
1043 rc));
1044 err = -RTErrConvertToErrno(rc);
1045 kfree(new_path);
1046 }
1047 }
1048 }
1049 return err;
1050}
1051
1052#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
1053static int vbsf_ino_symlink(struct inode *parent, struct dentry *dentry, const char *symname)
1054{
1055 int err;
1056 int rc;
1057 struct vbsf_inode_info *sf_i;
1058 struct vbsf_super_info *sf_g;
1059 SHFLSTRING *path, *ssymname;
1060 SHFLFSOBJINFO info;
1061 int symname_len = strlen(symname) + 1;
1062
1063 TRACE();
1064 sf_g = VBSF_GET_SUPER_INFO(parent->i_sb);
1065 sf_i = VBSF_GET_INODE_INFO(parent);
1066
1067 BUG_ON(!sf_g);
1068 BUG_ON(!sf_i);
1069
1070 err = vbsf_path_from_dentry(__func__, sf_g, sf_i, dentry, &path);
1071 if (err)
1072 goto fail0;
1073
1074 ssymname = kmalloc(offsetof(SHFLSTRING, String.utf8) + symname_len, GFP_KERNEL);
1075 if (!ssymname) {
1076 LogRelFunc(("kmalloc failed, caller=sf_symlink\n"));
1077 err = -ENOMEM;
1078 goto fail1;
1079 }
1080
1081 ssymname->u16Length = symname_len - 1;
1082 ssymname->u16Size = symname_len;
1083 memcpy(ssymname->String.utf8, symname, symname_len);
1084
1085 rc = VbglR0SfSymlink(&g_SfClient, &sf_g->map, path, ssymname, &info);
1086 kfree(ssymname);
1087
1088 if (RT_FAILURE(rc)) {
1089 err = RTErrConvertFromErrno(rc);
1090 LogFunc(("VbglR0SfSymlink(%s) failed rc=%Rrc\n", sf_i->path->String.utf8, rc));
1091 goto fail1;
1092 }
1093
1094 err = vbsf_inode_instantiate(parent, dentry, path, &info, SHFL_HANDLE_NIL);
1095 if (err) {
1096 LogFunc(("could not instantiate dentry for %s err=%d\n", sf_i->path->String.utf8, err));
1097 goto fail1;
1098 }
1099
1100 sf_i->force_restat = 1;
1101 return 0;
1102
1103 fail1:
1104 kfree(path);
1105 fail0:
1106 return err;
1107}
1108#endif /* LINUX_VERSION_CODE >= 2.6.0 */
1109
1110struct inode_operations vbsf_dir_iops = {
1111 .lookup = vbsf_inode_lookup,
1112 .create = vbsf_inode_create,
1113 .mkdir = vbsf_inode_mkdir,
1114 .rmdir = vbsf_inode_rmdir,
1115 .unlink = vbsf_inode_unlink,
1116 .rename = vbsf_inode_rename,
1117#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
1118 .revalidate = vbsf_inode_revalidate
1119#else
1120 .getattr = vbsf_inode_getattr,
1121 .setattr = vbsf_inode_setattr,
1122 .symlink = vbsf_ino_symlink
1123#endif
1124};
1125
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