xref: /kernel/liteos_a/fs/vfs/vnode.c (revision 0d163575)
1/*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 *    conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 *    of conditions and the following disclaimer in the documentation and/or other materials
12 *    provided with the distribution.
13 *
14 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
15 *    to endorse or promote products derived from this software without specific prior written
16 *    permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "los_mux.h"
32#include "fs/dirent_fs.h"
33#include "path_cache.h"
34#include "vnode.h"
35#include "los_process.h"
36#include "los_process_pri.h"
37
38LIST_HEAD g_vnodeFreeList;              /* free vnodes list */
39LIST_HEAD g_vnodeVirtualList;           /* dev vnodes list */
40LIST_HEAD g_vnodeActiveList;              /* inuse vnodes list */
41static int g_freeVnodeSize = 0;         /* system free vnodes size */
42static int g_totalVnodeSize = 0;        /* total vnode size */
43
44static LosMux g_vnodeMux;
45static struct Vnode *g_rootVnode = NULL;
46static struct VnodeOps g_devfsOps;
47
48#define ENTRY_TO_VNODE(ptr)  LOS_DL_LIST_ENTRY(ptr, struct Vnode, actFreeEntry)
49#define VNODE_LRU_COUNT      10
50#define DEV_VNODE_MODE       0755
51
52int VnodesInit(void)
53{
54    int retval = LOS_MuxInit(&g_vnodeMux, NULL);
55    if (retval != LOS_OK) {
56        PRINT_ERR("Create mutex for vnode fail, status: %d", retval);
57        return retval;
58    }
59
60    LOS_ListInit(&g_vnodeFreeList);
61    LOS_ListInit(&g_vnodeVirtualList);
62    LOS_ListInit(&g_vnodeActiveList);
63    retval = VnodeAlloc(NULL, &g_rootVnode);
64    if (retval != LOS_OK) {
65        PRINT_ERR("VnodeInit failed error %d\n", retval);
66        return retval;
67    }
68    g_rootVnode->mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFDIR;
69    g_rootVnode->type = VNODE_TYPE_DIR;
70    g_rootVnode->filePath = "/";
71
72#ifdef LOSCFG_CHROOT
73    LosProcessCB *processCB = OsGetKernelInitProcess();
74    if (processCB->files != NULL) {
75        g_rootVnode->useCount++;
76        processCB->files->rootVnode = g_rootVnode;
77    }
78#endif
79    return LOS_OK;
80}
81
82static struct Vnode *GetFromFreeList(void)
83{
84    if (g_freeVnodeSize <= 0) {
85        return NULL;
86    }
87    struct Vnode *vnode = NULL;
88
89    if (LOS_ListEmpty(&g_vnodeFreeList)) {
90        PRINT_ERR("get vnode from free list failed, list empty but g_freeVnodeSize = %d!\n", g_freeVnodeSize);
91        g_freeVnodeSize = 0;
92        return NULL;
93    }
94
95    vnode = ENTRY_TO_VNODE(LOS_DL_LIST_FIRST(&g_vnodeFreeList));
96    LOS_ListDelete(&vnode->actFreeEntry);
97    g_freeVnodeSize--;
98    return vnode;
99}
100
101struct Vnode *VnodeReclaimLru(void)
102{
103    struct Vnode *item = NULL;
104    struct Vnode *nextItem = NULL;
105    int releaseCount = 0;
106
107    LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(item, nextItem, &g_vnodeActiveList, struct Vnode, actFreeEntry) {
108        if ((item->useCount > 0) ||
109            (item->flag & VNODE_FLAG_MOUNT_ORIGIN) ||
110            (item->flag & VNODE_FLAG_MOUNT_NEW)) {
111            continue;
112        }
113
114        if (VnodeFree(item) == LOS_OK) {
115            releaseCount++;
116        }
117        if (releaseCount >= VNODE_LRU_COUNT) {
118            break;
119        }
120    }
121
122    if (releaseCount == 0) {
123        PRINT_ERR("VnodeAlloc failed, vnode size hit max but can't reclaim anymore!\n");
124        return NULL;
125    }
126
127    item = GetFromFreeList();
128    if (item == NULL) {
129        PRINT_ERR("VnodeAlloc failed, reclaim and get from free list failed!\n");
130    }
131    return item;
132}
133
134int VnodeAlloc(struct VnodeOps *vop, struct Vnode **newVnode)
135{
136    struct Vnode* vnode = NULL;
137
138    VnodeHold();
139    vnode = GetFromFreeList();
140    if ((vnode == NULL) && g_totalVnodeSize < LOSCFG_MAX_VNODE_SIZE) {
141        vnode = (struct Vnode *)zalloc(sizeof(struct Vnode));
142        g_totalVnodeSize++;
143    }
144
145    if (vnode == NULL) {
146        vnode = VnodeReclaimLru();
147    }
148
149    if (vnode == NULL) {
150        *newVnode = NULL;
151        VnodeDrop();
152        return -ENOMEM;
153    }
154
155    vnode->type = VNODE_TYPE_UNKNOWN;
156    LOS_ListInit((&(vnode->parentPathCaches)));
157    LOS_ListInit((&(vnode->childPathCaches)));
158    LOS_ListInit((&(vnode->hashEntry)));
159    LOS_ListInit((&(vnode->actFreeEntry)));
160
161    if (vop == NULL) {
162        LOS_ListAdd(&g_vnodeVirtualList, &(vnode->actFreeEntry));
163        vnode->vop = &g_devfsOps;
164    } else {
165        LOS_ListTailInsert(&g_vnodeActiveList, &(vnode->actFreeEntry));
166        vnode->vop = vop;
167    }
168    LOS_ListInit(&vnode->mapping.page_list);
169    LOS_SpinInit(&vnode->mapping.list_lock);
170    (VOID)LOS_MuxInit(&vnode->mapping.mux_lock, NULL);
171    vnode->mapping.host = vnode;
172
173    VnodeDrop();
174
175    *newVnode = vnode;
176
177    return LOS_OK;
178}
179
180int VnodeFree(struct Vnode *vnode)
181{
182    if (vnode == NULL) {
183        return LOS_OK;
184    }
185
186    VnodeHold();
187    if (vnode->useCount > 0) {
188        VnodeDrop();
189        return -EBUSY;
190    }
191
192    VnodePathCacheFree(vnode);
193    LOS_ListDelete(&(vnode->hashEntry));
194    LOS_ListDelete(&vnode->actFreeEntry);
195
196    if (vnode->vop->Reclaim) {
197        vnode->vop->Reclaim(vnode);
198    }
199
200    if (vnode->filePath) {
201        free(vnode->filePath);
202    }
203    if (vnode->vop == &g_devfsOps) {
204        /* for dev vnode, just free it */
205        free(vnode->data);
206        free(vnode);
207        g_totalVnodeSize--;
208    } else {
209        /* for normal vnode, reclaim it to g_VnodeFreeList */
210        (void)memset_s(vnode, sizeof(struct Vnode), 0, sizeof(struct Vnode));
211        LOS_ListAdd(&g_vnodeFreeList, &vnode->actFreeEntry);
212        g_freeVnodeSize++;
213    }
214    VnodeDrop();
215
216    return LOS_OK;
217}
218
219int VnodeFreeAll(const struct Mount *mount)
220{
221    struct Vnode *vnode = NULL;
222    struct Vnode *nextVnode = NULL;
223    int ret;
224
225    LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(vnode, nextVnode, &g_vnodeActiveList, struct Vnode, actFreeEntry) {
226        if ((vnode->originMount == mount) && !(vnode->flag & VNODE_FLAG_MOUNT_NEW)) {
227            ret = VnodeFree(vnode);
228            if (ret != LOS_OK) {
229                return ret;
230            }
231        }
232    }
233
234    return LOS_OK;
235}
236
237BOOL VnodeInUseIter(const struct Mount *mount)
238{
239    struct Vnode *vnode = NULL;
240
241    LOS_DL_LIST_FOR_EACH_ENTRY(vnode, &g_vnodeActiveList, struct Vnode, actFreeEntry) {
242        if (vnode->originMount == mount) {
243            if ((vnode->useCount > 0) || (vnode->flag & VNODE_FLAG_MOUNT_ORIGIN)) {
244                return TRUE;
245            }
246        }
247    }
248    return FALSE;
249}
250
251int VnodeHold(void)
252{
253    int ret = LOS_MuxLock(&g_vnodeMux, LOS_WAIT_FOREVER);
254    if (ret != LOS_OK) {
255        PRINT_ERR("VnodeHold lock failed !\n");
256    }
257    return ret;
258}
259
260int VnodeDrop(void)
261{
262    int ret = LOS_MuxUnlock(&g_vnodeMux);
263    if (ret != LOS_OK) {
264        PRINT_ERR("VnodeDrop unlock failed !\n");
265    }
266    return ret;
267}
268
269static char *NextName(char *pos, uint8_t *len)
270{
271    char *name = NULL;
272    while (*pos != 0 && *pos == '/') {
273        pos++;
274    }
275    if (*pos == '\0') {
276        return NULL;
277    }
278    name = (char *)pos;
279    while (*pos != '\0' && *pos != '/') {
280        pos++;
281    }
282    *len = pos - name;
283    return name;
284}
285
286static int PreProcess(const char *originPath, struct Vnode **startVnode, char **path)
287{
288    int ret;
289    char *absolutePath = NULL;
290
291    ret = vfs_normalize_path(NULL, originPath, &absolutePath);
292    if (ret == LOS_OK) {
293        *startVnode = GetCurrRootVnode();
294        *path = absolutePath;
295    }
296
297    return ret;
298}
299
300static struct Vnode *ConvertVnodeIfMounted(struct Vnode *vnode)
301{
302    if ((vnode == NULL) || !(vnode->flag & VNODE_FLAG_MOUNT_ORIGIN)) {
303        return vnode;
304    }
305#ifdef LOSCFG_MNT_CONTAINER
306    LIST_HEAD *mntList = GetMountList();
307    struct Mount *mnt = NULL;
308    LOS_DL_LIST_FOR_EACH_ENTRY(mnt, mntList, struct Mount, mountList) {
309        if ((mnt != NULL) && (mnt->vnodeBeCovered == vnode)) {
310            return mnt->vnodeCovered;
311        }
312    }
313    if (strcmp(vnode->filePath, "/dev") == 0) {
314        return vnode->newMount->vnodeCovered;
315    }
316    return vnode;
317#else
318    return vnode->newMount->vnodeCovered;
319#endif
320}
321
322static void RefreshLRU(struct Vnode *vnode)
323{
324    if (vnode == NULL || (vnode->type != VNODE_TYPE_REG && vnode->type != VNODE_TYPE_DIR) ||
325        vnode->vop == &g_devfsOps || vnode->vop == NULL) {
326        return;
327    }
328    LOS_ListDelete(&(vnode->actFreeEntry));
329    LOS_ListTailInsert(&g_vnodeActiveList, &(vnode->actFreeEntry));
330}
331
332static int ProcessVirtualVnode(struct Vnode *parent, uint32_t flags, struct Vnode **vnode)
333{
334    int ret = -ENOENT;
335    if (flags & V_CREATE) {
336        // only create /dev/ vnode
337        ret = VnodeAlloc(NULL, vnode);
338    }
339    if (ret == LOS_OK) {
340        (*vnode)->parent = parent;
341    }
342    return ret;
343}
344
345static int Step(char **currentDir, struct Vnode **currentVnode, uint32_t flags)
346{
347    int ret;
348    uint8_t len = 0;
349    struct Vnode *nextVnode = NULL;
350    char *nextDir = NULL;
351
352    if ((*currentVnode)->type != VNODE_TYPE_DIR) {
353        return -ENOTDIR;
354    }
355    nextDir = NextName(*currentDir, &len);
356    if (nextDir == NULL) {
357        // there is '/' at the end of the *currentDir.
358        *currentDir = NULL;
359        return LOS_OK;
360    }
361
362    ret = PathCacheLookup(*currentVnode, nextDir, len, &nextVnode);
363    if (ret == LOS_OK) {
364        goto STEP_FINISH;
365    }
366
367    (*currentVnode)->useCount++;
368    if (flags & V_DUMMY) {
369        ret = ProcessVirtualVnode(*currentVnode, flags, &nextVnode);
370    } else {
371        if ((*currentVnode)->vop != NULL && (*currentVnode)->vop->Lookup != NULL) {
372            ret = (*currentVnode)->vop->Lookup(*currentVnode, nextDir, len, &nextVnode);
373        } else {
374            ret = -ENOSYS;
375        }
376    }
377    (*currentVnode)->useCount--;
378
379    if (ret == LOS_OK) {
380        (void)PathCacheAlloc((*currentVnode), nextVnode, nextDir, len);
381    }
382
383STEP_FINISH:
384    nextVnode = ConvertVnodeIfMounted(nextVnode);
385    RefreshLRU(nextVnode);
386
387    *currentDir = nextDir + len;
388    if (ret == LOS_OK) {
389        *currentVnode = nextVnode;
390    }
391
392    return ret;
393}
394
395int VnodeLookupAt(const char *path, struct Vnode **result, uint32_t flags, struct Vnode *orgVnode)
396{
397    int ret;
398    int vnodePathLen;
399    char *vnodePath = NULL;
400    struct Vnode *startVnode = NULL;
401    char *normalizedPath = NULL;
402
403    if (orgVnode != NULL) {
404        startVnode = orgVnode;
405        normalizedPath = strdup(path);
406        if (normalizedPath == NULL) {
407            PRINT_ERR("[VFS]lookup failed, strdup err\n");
408            ret = -EINVAL;
409            goto OUT_FREE_PATH;
410        }
411    } else {
412        ret = PreProcess(path, &startVnode, &normalizedPath);
413        if (ret != LOS_OK) {
414            PRINT_ERR("[VFS]lookup failed, invalid path err = %d\n", ret);
415            goto OUT_FREE_PATH;
416        }
417    }
418
419    if (normalizedPath[1] == '\0' && normalizedPath[0] == '/') {
420        *result = GetCurrRootVnode();
421        free(normalizedPath);
422        return LOS_OK;
423    }
424
425    char *currentDir = normalizedPath;
426    struct Vnode *currentVnode = startVnode;
427
428    while (*currentDir != '\0') {
429        ret = Step(&currentDir, &currentVnode, flags);
430        if (currentDir == NULL || *currentDir == '\0') {
431            // return target or parent vnode as result
432            *result = currentVnode;
433            if (currentVnode->filePath == NULL) {
434                currentVnode->filePath = normalizedPath;
435            } else {
436                free(normalizedPath);
437            }
438            return ret;
439        } else if (VfsVnodePermissionCheck(currentVnode, EXEC_OP)) {
440            ret = -EACCES;
441            goto OUT_FREE_PATH;
442        }
443
444        if (ret != LOS_OK) {
445            // no such file, lookup failed
446            goto OUT_FREE_PATH;
447        }
448        if (currentVnode->filePath == NULL) {
449            vnodePathLen = currentDir - normalizedPath;
450            vnodePath = malloc(vnodePathLen + 1);
451            if (vnodePath == NULL) {
452                ret = -ENOMEM;
453                goto OUT_FREE_PATH;
454            }
455            ret = strncpy_s(vnodePath, vnodePathLen + 1, normalizedPath, vnodePathLen);
456            if (ret != EOK) {
457                ret = -ENAMETOOLONG;
458                free(vnodePath);
459                goto OUT_FREE_PATH;
460            }
461            currentVnode->filePath = vnodePath;
462            currentVnode->filePath[vnodePathLen] = 0;
463        }
464    }
465
466OUT_FREE_PATH:
467    if (normalizedPath) {
468        free(normalizedPath);
469    }
470    return ret;
471}
472
473int VnodeLookup(const char *path, struct Vnode **vnode, uint32_t flags)
474{
475    return VnodeLookupAt(path, vnode, flags, NULL);
476}
477
478int VnodeLookupFullpath(const char *fullpath, struct Vnode **vnode, uint32_t flags)
479{
480    return VnodeLookupAt(fullpath, vnode, flags, GetCurrRootVnode());
481}
482
483static void ChangeRootInternal(struct Vnode *rootOld, char *dirname)
484{
485    int ret;
486    struct Mount *mnt = NULL;
487    char *name = NULL;
488    struct Vnode *node = NULL;
489    struct Vnode *nodeInFs = NULL;
490    struct PathCache *item = NULL;
491    struct PathCache *nextItem = NULL;
492
493    LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(item, nextItem, &rootOld->childPathCaches, struct PathCache, childEntry) {
494        name = item->name;
495        node = item->childVnode;
496
497        if (strcmp(name, dirname)) {
498            continue;
499        }
500        PathCacheFree(item);
501
502        ret = VnodeLookup(dirname, &nodeInFs, 0);
503        if (ret) {
504            PRINTK("%s-%d %s NOT exist in rootfs\n", __FUNCTION__, __LINE__, dirname);
505            break;
506        }
507
508        mnt = node->newMount;
509        mnt->vnodeBeCovered = nodeInFs;
510
511        nodeInFs->newMount = mnt;
512        nodeInFs->flag |= VNODE_FLAG_MOUNT_ORIGIN;
513
514        break;
515    }
516}
517
518void ChangeRoot(struct Vnode *rootNew)
519{
520    struct Vnode *rootOld = g_rootVnode;
521    g_rootVnode = rootNew;
522#ifdef LOSCFG_CHROOT
523    LosProcessCB *curr = OsCurrProcessGet();
524    if ((curr->files != NULL) &&
525        (curr->files->rootVnode != NULL) &&
526        (curr->files->rootVnode->useCount > 0)) {
527        curr->files->rootVnode->useCount--;
528    }
529    rootNew->useCount++;
530    curr->files->rootVnode = rootNew;
531#endif
532
533    ChangeRootInternal(rootOld, "proc");
534    ChangeRootInternal(rootOld, "dev");
535}
536
537static int VnodeReaddir(struct Vnode *vp, struct fs_dirent_s *dir)
538{
539    int result;
540    int cnt = 0;
541    off_t i = 0;
542    off_t idx;
543    unsigned int dstNameSize;
544
545    struct PathCache *item = NULL;
546    struct PathCache *nextItem = NULL;
547
548    if (dir == NULL) {
549        return -EINVAL;
550    }
551
552    LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(item, nextItem, &vp->childPathCaches, struct PathCache, childEntry) {
553        if (i < dir->fd_position) {
554            i++;
555            continue;
556        }
557
558        idx = i - dir->fd_position;
559
560        dstNameSize = sizeof(dir->fd_dir[idx].d_name);
561        result = strncpy_s(dir->fd_dir[idx].d_name, dstNameSize, item->name, item->nameLen);
562        if (result != EOK) {
563            return -ENAMETOOLONG;
564        }
565        dir->fd_dir[idx].d_off = i;
566        dir->fd_dir[idx].d_reclen = (uint16_t)sizeof(struct dirent);
567
568        i++;
569        if (++cnt >= dir->read_cnt) {
570            break;
571        }
572    }
573
574    dir->fd_position = i;
575
576    return cnt;
577}
578
579int VnodeOpendir(struct Vnode *vnode, struct fs_dirent_s *dir)
580{
581    (void)vnode;
582    (void)dir;
583    return LOS_OK;
584}
585
586int VnodeClosedir(struct Vnode *vnode, struct fs_dirent_s *dir)
587{
588    (void)vnode;
589    (void)dir;
590    return LOS_OK;
591}
592
593int VnodeCreate(struct Vnode *parent, const char *name, int mode, struct Vnode **vnode)
594{
595    int ret;
596    struct Vnode *newVnode = NULL;
597
598    ret = VnodeAlloc(NULL, &newVnode);
599    if (ret != 0) {
600        return -ENOMEM;
601    }
602
603    newVnode->type = VNODE_TYPE_CHR;
604    newVnode->vop = parent->vop;
605    newVnode->fop = parent->fop;
606    newVnode->data = NULL;
607    newVnode->parent = parent;
608    newVnode->originMount = parent->originMount;
609    newVnode->uid = parent->uid;
610    newVnode->gid = parent->gid;
611    newVnode->mode = mode;
612    /* The 'name' here is not full path, but for device we don't depend on this path, it's just a name for DFx.
613       When we have devfs, we can get a fullpath. */
614    newVnode->filePath = strdup(name);
615
616    *vnode = newVnode;
617    return 0;
618}
619
620int VnodeDevInit(void)
621{
622    struct Vnode *devNode = NULL;
623    struct Mount *devMount = NULL;
624
625    int retval = VnodeLookup("/dev", &devNode, V_CREATE | V_DUMMY);
626    if (retval != LOS_OK) {
627        PRINT_ERR("VnodeDevInit failed error %d\n", retval);
628        return retval;
629    }
630    devNode->mode = DEV_VNODE_MODE | S_IFDIR;
631    devNode->type = VNODE_TYPE_DIR;
632
633    devMount = MountAlloc(devNode, NULL);
634    if (devMount == NULL) {
635        PRINT_ERR("VnodeDevInit failed mount point alloc failed.\n");
636        return -ENOMEM;
637    }
638    devMount->vnodeCovered = devNode;
639    devMount->vnodeBeCovered->flag |= VNODE_FLAG_MOUNT_ORIGIN;
640    return LOS_OK;
641}
642
643int VnodeGetattr(struct Vnode *vnode, struct stat *buf)
644{
645    (void)memset_s(buf, sizeof(struct stat), 0, sizeof(struct stat));
646    buf->st_mode = vnode->mode;
647    buf->st_uid = vnode->uid;
648    buf->st_gid = vnode->gid;
649
650    return LOS_OK;
651}
652
653struct Vnode *VnodeGetRoot(void)
654{
655    return g_rootVnode;
656}
657
658static int VnodeChattr(struct Vnode *vnode, struct IATTR *attr)
659{
660    mode_t tmpMode;
661    if (vnode == NULL || attr == NULL) {
662        return -EINVAL;
663    }
664    if (attr->attr_chg_valid & CHG_MODE) {
665        tmpMode = attr->attr_chg_mode;
666        tmpMode &= ~S_IFMT;
667        vnode->mode &= S_IFMT;
668        vnode->mode = tmpMode | vnode->mode;
669    }
670    if (attr->attr_chg_valid & CHG_UID) {
671        vnode->uid = attr->attr_chg_uid;
672    }
673    if (attr->attr_chg_valid & CHG_GID) {
674        vnode->gid = attr->attr_chg_gid;
675    }
676    return LOS_OK;
677}
678
679int VnodeDevLookup(struct Vnode *parentVnode, const char *path, int len, struct Vnode **vnode)
680{
681    (void)parentVnode;
682    (void)path;
683    (void)len;
684    (void)vnode;
685    /* dev node must in pathCache. */
686    return -ENOENT;
687}
688
689static struct VnodeOps g_devfsOps = {
690    .Lookup = VnodeDevLookup,
691    .Getattr = VnodeGetattr,
692    .Readdir = VnodeReaddir,
693    .Opendir = VnodeOpendir,
694    .Closedir = VnodeClosedir,
695    .Create = VnodeCreate,
696    .Chattr = VnodeChattr,
697};
698
699void VnodeMemoryDump(void)
700{
701    struct Vnode *item = NULL;
702    struct Vnode *nextItem = NULL;
703    int vnodeCount = 0;
704
705    LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(item, nextItem, &g_vnodeActiveList, struct Vnode, actFreeEntry) {
706        if ((item->useCount > 0) ||
707            (item->flag & VNODE_FLAG_MOUNT_ORIGIN) ||
708            (item->flag & VNODE_FLAG_MOUNT_NEW)) {
709            continue;
710        }
711
712        vnodeCount++;
713    }
714
715    PRINTK("Vnode number = %d\n", vnodeCount);
716    PRINTK("Vnode memory size = %d(B)\n", vnodeCount * sizeof(struct Vnode));
717}
718
719#ifdef LOSCFG_PROC_PROCESS_DIR
720struct Vnode *VnodeFind(int fd)
721{
722    INT32 sysFd;
723
724    if (fd < 0) {
725        PRINT_ERR("Error. fd is invalid as %d\n", fd);
726        return NULL;
727    }
728
729    /* Process fd convert to system global fd */
730    sysFd = GetAssociatedSystemFd(fd);
731    if (sysFd < 0) {
732        PRINT_ERR("Error. sysFd is invalid as %d\n", sysFd);
733        return NULL;
734    }
735
736    return files_get_openfile((int)sysFd);
737}
738#endif
739
740LIST_HEAD* GetVnodeFreeList()
741{
742    return &g_vnodeFreeList;
743}
744
745LIST_HEAD* GetVnodeVirtualList()
746{
747    return &g_vnodeVirtualList;
748}
749
750LIST_HEAD* GetVnodeActiveList()
751{
752    return &g_vnodeActiveList;
753}
754
755int VnodeClearCache(void)
756{
757    struct Vnode *item = NULL;
758    struct Vnode *nextItem = NULL;
759    int count = 0;
760
761    VnodeHold();
762    LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(item, nextItem, &g_vnodeActiveList, struct Vnode, actFreeEntry) {
763        if ((item->useCount > 0) ||
764            (item->flag & VNODE_FLAG_MOUNT_ORIGIN) ||
765            (item->flag & VNODE_FLAG_MOUNT_NEW)) {
766            continue;
767        }
768
769        if (VnodeFree(item) == LOS_OK) {
770            count++;
771        }
772    }
773    VnodeDrop();
774
775    return count;
776}
777
778struct Vnode *GetCurrRootVnode(void)
779{
780#ifdef LOSCFG_CHROOT
781    LosProcessCB *curr = OsCurrProcessGet();
782    return curr->files->rootVnode;
783#else
784    return g_rootVnode;
785#endif
786}
787