• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# File System Adaptation<a name="EN-US_TOPIC_0000001078936814"></a>
2
3-   [Basic Concepts](#section19480121811422)
4-   [Adapting the Mount API](#section147051940104212)
5-   [Adapting the Lookup API](#section11930181394317)
6-   [Summary and Precautions](#section5617183014319)
7
8## Basic Concepts<a name="section19480121811422"></a>
9
10The purpose of interconnecting with the VFS layer is to implement API functions defined by the VFS layer. You can adapt some APIs based on the file system features and service requirements. Basically, file read and write must be supported. The minimum file system adaptation is as follows:
11
12```
13struct MountOps g_yourFsMountOps = {
14    .Mount = YourMountMethod,
15};
16
17struct file_operations_vfs g_yourFsFileOps = {
18  .read = YourReadMethod,
19  .write = YourWriteMethod,
20}
21
22struct VnodeOps g_yourFsVnodeOps = {
23    .Create = YourCreateMethod;
24    .Lookup = YourLookupMethod;
25    .Reclaim = YourReclaimMethod;
26};
27
28FSMAP_ENTRY(yourfs_fsmap, "your fs name", g_yourFsMountOps, TRUE, TRUE); // Register the file system.
29```
30
31>![](../public_sys-resources/icon-note.gif) **NOTE:**
32>1.  The  **open**  and  **close**  APIs are not necessarily implemented because they are used to operate files and are imperceptible to the underlying file system. You need to implement these APIs only when special operations need to be performed during the open and close operations on the file system.
33>2.  Basic file system knowledge is required for file system adaptation. You need to have a deep understanding of the principles and implementation of the target file system. This section does not include the file system basics in detail. If you have any questions during the adaptation process, refer to the code in the  **kernel/liteos\_a/fs**  directory.
34
35## Adapting the Mount API<a name="section147051940104212"></a>
36
37**Mount**  is the first API called by the file system. This API reads the driver parameters, initializes the file system based on the configuration, and generates the root node of the file system. The  **Mount**  API is defined as follows:
38
39```
40int (*Mount)(struct Mount *mount, struct Vnode *blkDriver, const void *data);
41```
42
43The parameter  **struct Mount \*mount**  specifies information about the mount point. The following variables need to be set during adaptation:
44
45```
46struct Mount {
47    const struct MountOps *ops;        /* Mount-related function hooks */
48    struct Vnode *vnodeCovered;        /* root node of the file system generated after the mount*/
49    void *data;                        /* Private data of the mount point*/
50};
51```
52
53The parameter  **struct Vnode \*blkDriver**  specifies the driver node, which can be used to access the driver.
54
55The parameter  **const void \*data**  specifies the data passed by the  **mount**  command and can be processed according to the requirements of the file system.
56
57The following uses JFFS2 as an example to describe how the adapt the  **mount**  API:
58
59```
60int VfsJffs2Bind(struct Mount *mnt, struct Vnode *blkDriver, const void *data)
61{
62    int ret;
63    int partNo;
64    mtd_partition *p = NULL;
65    struct MtdDev *mtd = NULL;
66    struct Vnode *pv = NULL;
67    struct jffs2_inode *rootNode = NULL;
68
69    LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER);
70
71    /* Obtain information required by the file system from the driver node, for example, the partition ID for the JFFS2. */
72    p = (mtd_partition *)((struct drv_data *)blkDriver->data)->priv;
73    mtd = (struct MtdDev *)(p->mtd_info);
74
75    if (mtd == NULL || mtd->type != MTD_NORFLASH) {
76        LOS_MuxUnlock(&g_jffs2FsLock);
77        return -EINVAL;
78    }
79
80    partNo = p->patitionnum;
81
82    /* Generate a root Vnode for the file system. Do not mix rootNode and root Vnode. The rootNode type is inode, which is the private data maintained in JFFS2. Vnode is a common file node of VFS.
83       This step saves the private information in the file system to the Vnode. As a result, you can directly find the corresponding file in the file system through the Vnode.
84     */
85    ret = jffs2_mount(partNo, &rootNode);
86    if (ret != 0) {
87        LOS_MuxUnlock(&g_jffs2FsLock);
88        return ret;
89    }
90
91    ret = VnodeAlloc(&g_jffs2Vops, &pv);
92    if (ret != 0) {
93        LOS_MuxUnlock(&g_jffs2FsLock);
94        goto ERROR_WITH_VNODE;
95    }
96
97    /* The following enters information about the file corresponding to the Vnode. Some file systems may not support uid, gid, and mode, which can be skipped.*/
98    pv->type = VNODE_TYPE_DIR;
99    pv->data = (void *)rootNode;
100    pv->originMount = mnt;
101    pv->fop = &g_jffs2Fops;
102    mnt->data = p;
103    mnt->vnodeCovered = pv;
104    pv->uid = rootNode->i_uid;
105    pv->gid = rootNode->i_gid;
106    pv->mode = rootNode->i_mode;
107
108    /* HashInsert is used to prevent repeated generation of Vnodes. The second parameter is generally set to the unique file identifier in the file system, for example, the inode address in JFFS2. */
109    (void)VfsHashInsert(pv, rootNode->i_ino);
110
111    g_jffs2PartList[partNo] = blkDriver;
112
113    LOS_MuxUnlock(&g_jffs2FsLock);
114
115    return 0;
116ERROR_WITH_VNODE:
117    return ret;
118}
119...
120...
121const struct MountOps jffs_operations = {
122    .Mount = VfsJffs2Bind,
123    ...
124    ...
125};
126```
127
128Summary:
129
1301.  Obtain the required private information from the driver node.
1312.  Generate the root node of the file system based on the private information.
132
133## Adapting the  **Lookup**  API<a name="section11930181394317"></a>
134
135**Lookup**  is used to search for files. The function prototype of  **Lookup**  is:
136
137```
138int (*Lookup)(struct Vnode *parent, const char *name, int len, struct Vnode **vnode);
139```
140
141This function searches for the Vnode from the parent node based on the file name \(**name**\) and file name length \(**len**\) and returns the Vnode to the upper layer.
142
143You need to specify the parent node information and file name to implement search for the file of the specified name under the parent directory. The following uses JFFS2 as an example:
144
145```
146int VfsJffs2Lookup(struct Vnode *parentVnode, const char *path, int len, struct Vnode **ppVnode)
147{
148    int ret;
149    struct Vnode *newVnode = NULL;
150    struct jffs2_inode *node = NULL;
151    struct jffs2_inode *parentNode = NULL;
152
153    LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER);
154
155    /* Obtain information about the parent node from the private data.*/
156    parentNode = (struct jffs2_inode *)parentVnode->data;
157
158    /* Obtain information about the target node. Note that the jffs2_lookup function called is a function of JFFS2. */
159    node = jffs2_lookup(parentNode, (const unsigned char *)path, len);
160    if (!node) {
161        LOS_MuxUnlock(&g_jffs2FsLock);
162        return -ENOENT;
163    }
164
165    /* Check whether the located target has an existing vnode, which corresponds to VfsHashInsert mentioned earlier. */
166    (void)VfsHashGet(parentVnode->originMount, node->i_ino, &newVnode, NULL, NULL);
167    LOS_MuxUnlock(&g_jffs2FsLock);
168    if (newVnode) {
169        newVnode->parent = parentVnode;
170        *ppVnode = newVnode;
171        return 0;
172    }
173
174    /* If the Vnode does not exist, create a Vnode and enter related information. */
175    ret = VnodeAlloc(&g_jffs2Vops, &newVnode);
176    if (ret != 0) {
177        PRINT_ERR("%s-%d, ret: %x\n", __FUNCTION__, __LINE__, ret);
178        (void)jffs2_iput(node);
179        LOS_MuxUnlock(&g_jffs2FsLock);
180        return ret;
181    }
182
183    Jffs2SetVtype(node, newVnode);
184    newVnode->fop = parentVnode->fop;
185    newVnode->data = node;
186    newVnode->parent = parentVnode;
187    newVnode->originMount = parentVnode->originMount;
188    newVnode->uid = node->i_uid;
189    newVnode->gid = node->i_gid;
190    newVnode->mode = node->i_mode;
191
192    /* Insert the newly created Vnode into the hashtable.*/
193    (void)VfsHashInsert(newVnode, node->i_ino);
194
195    *ppVnode = newVnode;
196
197    LOS_MuxUnlock(&g_jffs2FsLock);
198    return 0;
199}
200```
201
202Summary:
203
2041.  Obtain private data from the parent node.
2052.  Obtain the private data of the target file based on the private data.
2063.  Create the target Vnode based on the private data of the target file.
207
208## Summary and Precautions<a name="section5617183014319"></a>
209
210The general adaptation procedure is as follows:
211
2121.  Obtain the private data required by the file system based on the Vnode input parameters.
2132.  Implement the API based on the private data.
2143.  Encapsulate the result in the format required by the Vnode or other APIs and return the result to the upper layer.
215
216The core logic is how to use the private data to implement API functions. These APIs implement common functions of the file systems and are generally implemented before the files systems are ported. Therefore, the key is to determine the private data required by the file system and store the data in Vnode for later use. Generally, the private data is information that can uniquely locate a file on a storage medium. Most file systems have similar data structures, for example, the inode data structure in JFFS2.
217
218>![](../public_sys-resources/icon-caution.gif) **CAUTION:**
219>1.  When a file is accessed, the  **Lookup**  API of the file system is not necessrily called. The  **Lookup**  API is called only when the path cache is invalid.
220>2.  Do not directly return the Vnode located by using  **VfsHashGet**  as the result. The information stored in the Vnode may be invalid. Update the fields and return it.
221>3.  Vnodes are automatically released in the background based on memory usage. If data needs to be stored persistently, do not save it only in Vnodes.
222>4.  The  **Reclaim**  API is automatically called when a Vnode is released. Release the resources used by the private data in this API.
223
224