VirtualBox

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

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

linux/vboxsf: Some cleanups and logging in dirops.c. bugref:9172

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