1# File System Adaptation 2 3 4## Basic Concepts<a name="section19480121811422"></a> 5 6The 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: 7 8``` 9struct MountOps g_yourFsMountOps = { 10 .Mount = YourMountMethod, 11}; 12 13struct file_operations_vfs g_yourFsFileOps = { 14 .read = YourReadMethod, 15 .write = YourWriteMethod, 16} 17 18struct VnodeOps g_yourFsVnodeOps = { 19 .Create = YourCreateMethod; 20 .Lookup = YourLookupMethod; 21 .Reclaim = YourReclaimMethod; 22}; 23 24FSMAP_ENTRY(yourfs_fsmap, "your fs name", g_yourFsMountOps, TRUE, TRUE); // Register the file system. 25``` 26 27>![](../public_sys-resources/icon-note.gif) **NOTE**<br/> 28>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 them only when special operations need to be performed during the open and close operations on the file system. 29>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. 30 31## Adapting the Mount API<a name="section147051940104212"></a> 32 33**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: 34 35``` 36int (*Mount)(struct Mount *mount, struct Vnode *blkDriver, const void *data); 37``` 38 39The parameter **struct Mount \*mount** specifies information about the mount point. The following variables need to be set during adaptation: 40 41``` 42struct Mount { 43 const struct MountOps *ops; /* Mount-related function hooks */ 44 struct Vnode *vnodeCovered; /* root node of the file system generated after the mount*/ 45 void *data; /* Private data of the mount point*/ 46}; 47``` 48 49The parameter **struct Vnode \*blkDriver** specifies the driver node, which can be used to access the driver. 50 51The parameter **const void \*data** specifies the data passed by the **mount** command and can be processed according to the requirements of the file system. 52 53The following uses JFFS2 as an example to describe how to adapt the **mount** API: 54 55``` 56int VfsJffs2Bind(struct Mount *mnt, struct Vnode *blkDriver, const void *data) 57{ 58 int ret; 59 int partNo; 60 mtd_partition *p = NULL; 61 struct MtdDev *mtd = NULL; 62 struct Vnode *pv = NULL; 63 struct jffs2_inode *rootNode = NULL; 64 65 LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER); 66 67 /* Obtain information required by the file system from the driver node, for example, the partition ID for JFFS2. */ 68 p = (mtd_partition *)((struct drv_data *)blkDriver->data)->priv; 69 mtd = (struct MtdDev *)(p->mtd_info); 70 71 if (mtd == NULL || mtd->type != MTD_NORFLASH) { 72 LOS_MuxUnlock(&g_jffs2FsLock); 73 return -EINVAL; 74 } 75 76 partNo = p->patitionnum; 77 78 /* 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. 79 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. 80 */ 81 ret = jffs2_mount(partNo, &rootNode); 82 if (ret != 0) { 83 LOS_MuxUnlock(&g_jffs2FsLock); 84 return ret; 85 } 86 87 ret = VnodeAlloc(&g_jffs2Vops, &pv); 88 if (ret != 0) { 89 LOS_MuxUnlock(&g_jffs2FsLock); 90 goto ERROR_WITH_VNODE; 91 } 92 93 /* 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.*/ 94 pv->type = VNODE_TYPE_DIR; 95 pv->data = (void *)rootNode; 96 pv->originMount = mnt; 97 pv->fop = &g_jffs2Fops; 98 mnt->data = p; 99 mnt->vnodeCovered = pv; 100 pv->uid = rootNode->i_uid; 101 pv->gid = rootNode->i_gid; 102 pv->mode = rootNode->i_mode; 103 104 /* 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. */ 105 (void)VfsHashInsert(pv, rootNode->i_ino); 106 107 g_jffs2PartList[partNo] = blkDriver; 108 109 LOS_MuxUnlock(&g_jffs2FsLock); 110 111 return 0; 112ERROR_WITH_VNODE: 113 return ret; 114} 115... 116... 117const struct MountOps jffs_operations = { 118 .Mount = VfsJffs2Bind, 119 ... 120 ... 121}; 122``` 123 124Summary: 125 1261. Obtain the required private information from the driver node. 1272. Generate the root node of the file system based on the private information. 128 129## Adapting the **Lookup** API<a name="section11930181394317"></a> 130 131**Lookup** is used to search for files. The function prototype of **Lookup** is as follows: 132 133``` 134int (*Lookup)(struct Vnode *parent, const char *name, int len, struct Vnode **vnode); 135``` 136 137This 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. 138 139You 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: 140 141``` 142int VfsJffs2Lookup(struct Vnode *parentVnode, const char *path, int len, struct Vnode **ppVnode) 143{ 144 int ret; 145 struct Vnode *newVnode = NULL; 146 struct jffs2_inode *node = NULL; 147 struct jffs2_inode *parentNode = NULL; 148 149 LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER); 150 151 /* Obtain information about the parent node from the private data.*/ 152 parentNode = (struct jffs2_inode *)parentVnode->data; 153 154 /* Obtain information about the target node. Note that the jffs2_lookup function called is a function of JFFS2. */ 155 node = jffs2_lookup(parentNode, (const unsigned char *)path, len); 156 if (!node) { 157 LOS_MuxUnlock(&g_jffs2FsLock); 158 return -ENOENT; 159 } 160 161 /* Check whether the located target has an existing Vnode, which corresponds to VfsHashInsert mentioned earlier. */ 162 (void)VfsHashGet(parentVnode->originMount, node->i_ino, &newVnode, NULL, NULL); 163 LOS_MuxUnlock(&g_jffs2FsLock); 164 if (newVnode) { 165 newVnode->parent = parentVnode; 166 *ppVnode = newVnode; 167 return 0; 168 } 169 170 /* If the Vnode does not exist, create a Vnode and enter related information. */ 171 ret = VnodeAlloc(&g_jffs2Vops, &newVnode); 172 if (ret != 0) { 173 PRINT_ERR("%s-%d, ret: %x\n", __FUNCTION__, __LINE__, ret); 174 (void)jffs2_iput(node); 175 LOS_MuxUnlock(&g_jffs2FsLock); 176 return ret; 177 } 178 179 Jffs2SetVtype(node, newVnode); 180 newVnode->fop = parentVnode->fop; 181 newVnode->data = node; 182 newVnode->parent = parentVnode; 183 newVnode->originMount = parentVnode->originMount; 184 newVnode->uid = node->i_uid; 185 newVnode->gid = node->i_gid; 186 newVnode->mode = node->i_mode; 187 188 /* Insert the newly created Vnode into the hashtable.*/ 189 (void)VfsHashInsert(newVnode, node->i_ino); 190 191 *ppVnode = newVnode; 192 193 LOS_MuxUnlock(&g_jffs2FsLock); 194 return 0; 195} 196``` 197 198Summary: 199 2001. Obtain private data from the parent node. 2012. Obtain the private data of the target file based on the private data. 2023. Create the target Vnode based on the private data of the target file. 203 204## Summary and Precautions<a name="section5617183014319"></a> 205 206The general adaptation procedure is as follows: 207 2081. Obtain the private data required by the file system based on the Vnode input parameters. 2092. Implement the API based on the private data. 2103. Encapsulate the result in the format required by the Vnode or other APIs and return the result to the upper layer. 211 212The 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 the 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. 213 214>![](../public_sys-resources/icon-caution.gif) **CAUTION:**<br/> 215>1. When a file is accessed, the **Lookup** API of the file system is not necessarily called. The **Lookup** API is called only when the PathCache is invalid. 216>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. 217>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. 218>4. The **Reclaim** API is automatically called when a Vnode is released. Release the resources used by the private data in this API. 219 220