更新日期: 2022/06/01 来源: https://gitee.com/weharmony/kernel_liteos_a_note
vfs_file_mapping.c
浏览该文件的文档.
1/*
2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 * conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 * of conditions and the following disclaimer in the documentation and/or other materials
13 * provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16 * to endorse or promote products derived from this software without specific prior written
17 * permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include "fs/file.h"
33#include "fs/file.h"
34#include "fs/fs_operation.h"
35#include "unistd.h"
36#include "los_mux.h"
37#include "los_list.h"
38#include "los_atomic.h"
39#include "los_vm_filemap.h"
40
41#ifdef LOSCFG_KERNEL_VM
42
43static struct file_map g_file_mapping = {0}; ///< 用于挂载所有文件的file_map
44
45#if 0
46定义见于 ..\third_party\NuttX\include\nuttx\fs\fs.h
47typedef volatile INT32 Atomic;
48//page_mapping描述的是一个文件在内存中被映射了多少页,<文件,文件页的关系>
49/* file mapped in VMM pages */
50struct page_mapping {//记录文件页和文件关系的结构体,叫文件页映射
51 LOS_DL_LIST page_list; /* all pages */ //链表上挂的是属于该文件的所有FilePage,这些页的内容都来源同一个文件
52 SPIN_LOCK_S list_lock; /* lock protecting it */ //操作page_list的自旋锁
53 LosMux mux_lock; /* mutex lock */ // //操作page_mapping的互斥量
54 unsigned long nrpages; /* number of total pages */ //page_list的节点数量
55 unsigned long flags; //@note_why 全量代码中也没查到源码中对其操作
56 Atomic ref; /* reference counting */ //引用次数(自增/自减),对应add_mapping/dec_mapping
57 struct file *host; /* owner of this mapping *///属于哪个文件的映射
58};
59
60/* map: full_path(owner) <-> mapping */ //叫文件映射
61struct file_map { //为在内核层面文件在内存的身份证,每个需映射到内存的文件必须创建一个file_map,都挂到全局g_file_mapping链表上
62 LOS_DL_LIST head; //链表节点,用于挂到g_file_mapping上
63 LosMux lock; /* lock to protect this mapping */
64 struct page_mapping mapping; //每个文件都有唯一的page_mapping标识其在内存的身份
65 char *owner; /* owner: full path of file *///文件全路径来标识唯一性
66};
67
68struct file //文件系统最重要的两个结构体之一,另一个是inode
69{
70 unsigned int f_magicnum; /* file magic number */ //文件魔法数字
71 int f_oflags; /* Open mode flags */ //打开模式标签
72 FAR struct inode *f_inode; /* Driver interface */ //设备驱动程序
73 loff_t f_pos; /* File position */ //文件的位置
74 unsigned long f_refcount; /* reference count */ //被引用的数量,一个文件可被多个进程打开
75 char *f_path; /* File fullpath */ //全路径
76 void *f_priv; /* Per file driver private data */ //文件私有数据
77 const char *f_relpath; /* realpath */ //真实路径
78 struct page_mapping *f_mapping; /* mapping file to memory */ //与内存的映射 page-cache
79 void *f_dir; /* DIR struct for iterate the directory if open a directory */ //所在目录
80};
81
82#endif
83
84
85/*!
86 * @brief
87 * @verbatim
88 初始化文件映射模块,
89 file_map: 每个需映射到内存的文件必须创建一个 file_map,都挂到全局g_file_mapping链表上
90 page_mapping: 记录的是<文件,文件页>的关系,一个文件在操作过程中被映射成了多少个页,
91 file:是文件系统管理层面的概念
92 @endverbatim
93 * @return uint
94 */
96{
97 uint ret;
98
99 LOS_ListInit(&g_file_mapping.head);//初始化全局文件映射节点,所有文件的映射都将g_file_mapping.head挂在链表上
100
101 ret = LOS_MuxInit(&g_file_mapping.lock, NULL);//初始化文件映射互斥锁
102 if (ret != LOS_OK) {
103 PRINT_ERR("Create mutex for file map of page cache failed, (ret=%u)\n", ret);
104 }
105
106 return ret;
107}
108///清除文件映射
109static void clear_file_mapping(const struct page_mapping *mapping)
110{
111 unsigned int i = 3; /* file start fd */
112 struct file *filp = NULL;
113
114 while (i < CONFIG_NFILE_DESCRIPTORS) {
115 filp = &tg_filelist.fl_files[i];
116 if (filp->f_mapping == mapping) {
117 filp->f_mapping = NULL;
118 }
119 i++;
120 }
121}
122///以无锁的方式通过文件名查找文件映射并返回
123static struct page_mapping *find_mapping_nolock(const char *fullpath)
124{
125 char *map_name = NULL;
126 struct file_map *fmap = NULL;
127 int name_len = strlen(fullpath);
128
129 LOS_DL_LIST_FOR_EACH_ENTRY(fmap, &g_file_mapping.head, struct file_map, head) {
130 map_name = fmap->rename ? fmap->rename: fmap->owner;
131 if ((name_len == fmap->name_len) && !strcmp(map_name, fullpath)) {
132 return &fmap->mapping;
133 }
134 }
135
136 return NULL;
137}
138
139
140/**
141 * @brief 增加一个文件映射,这个函数被do_open()函数调用,每打开一次文件就会调用一次
142 注意不同的进程打开同一个文件,拿到的file是不一样的。
143 https://blog.csdn.net/cywosp/article/details/38965239
144 * @param filep
145 * @param fullpath
146 */
147void add_mapping(struct file *filep, const char *fullpath)
148{
149 int path_len;
150 status_t retval;
151 struct file_map *fmap = NULL;
152 struct page_mapping *mapping = NULL;
153
154 if (filep == NULL || fullpath == NULL) {
155 return;
156 }
157
158 (VOID)LOS_MuxLock(&g_file_mapping.lock, LOS_WAIT_FOREVER);//操作临界区,先拿锁
159 mapping = find_mapping_nolock(fullpath);//是否已有文件映射
160 if (mapping) {
161 LOS_AtomicInc(&mapping->ref);//引用自增
162 filep->f_mapping = mapping;//记录page_mapping的老板
163 mapping->host = filep;//释放锁
164 goto out;
165 }
166
167 path_len = strlen(fullpath);
168
169 fmap = (struct file_map *)zalloc(sizeof(struct file_map) + path_len + 1);
170 if (!fmap) {
171 PRINT_WARN("%s %d, Mem alloc failed.\n", __FUNCTION__, __LINE__);
172 goto out;
173 }
174
175 LOS_AtomicSet(&fmap->mapping.ref, 1);
176
177 fmap->name_len = path_len;
178 (void)strcpy_s(fmap->owner, path_len + 1, fullpath);
179
180 LOS_ListInit(&fmap->mapping.page_list);//初始化文件映射的页表链表,上面将会挂这个文件映射的所有虚拟内存页
181 LOS_SpinInit(&fmap->mapping.list_lock);//初始化文件映射的自旋锁
182 retval = LOS_MuxInit(&fmap->mapping.mux_lock, NULL);//初始化文件映射的互斥锁
183 if (retval != LOS_OK) {
184 PRINT_ERR("%s %d, Create mutex for mapping.mux_lock failed, status: %d\n", __FUNCTION__, __LINE__, retval);
185 goto out;
186 }
187
188 LOS_ListTailInsert(&g_file_mapping.head, &fmap->head);//将文件映射结点挂入全局链表
189
190 filep->f_mapping = &fmap->mapping;//<file,file_map>之间互绑
191 filep->f_mapping->host = filep;//<file,file_map>之间互绑,从此相亲相爱一家人
192
193out:
195}
196
197
198
199/**
200 * @brief 删除一个文件映射,需要有个三个地方删除才算断开了文件和内存的联系.
201 以无锁的方式删除映射
202 * @param mapping
203 * @return int
204 */
206{
207 struct file_map *fmap = NULL;
208
209 if (mapping == NULL) {
210 set_errno(EINVAL);
211 return EINVAL;
212 }
213
217 fmap = LOS_DL_LIST_ENTRY(mapping, struct file_map, mapping);
218 LOS_ListDelete(&fmap->head);
219 if (fmap->rename) {
220 LOS_MemFree(m_aucSysMem0, fmap->rename);
221 }
223
224 return OK;
225}
226///无锁方式引用递减,删除或关闭文件时 由 files_close_internal调用
228{
229 if (mapping == NULL) {
230 return;
231 }
232
233 (VOID)LOS_MuxLock(&g_file_mapping.lock, LOS_WAIT_FOREVER);
234 if (LOS_AtomicRead(&mapping->ref) > 0) {
236 }
237
238 if (LOS_AtomicRead(&mapping->ref) <= 0) {
240 } else {
242 }
243
245}
246///已有锁的方式删除文件映射
247int remove_mapping(const char *fullpath)
248{
249 int ret;
250 struct filelist *f_list = NULL;
251 struct page_mapping *mapping = NULL;
252
253 f_list = &tg_filelist;
254 ret = sem_wait(&f_list->fl_sem);
255 if (ret < 0) {
256 PRINTK("sem_wait error, ret=%d\n", ret);
257 return VFS_ERROR;
258 }
259
260 (VOID)LOS_MuxLock(&g_file_mapping.lock, LOS_WAIT_FOREVER);
261
262 mapping = find_mapping_nolock(fullpath);
263 if (mapping) {
264 ret = remove_mapping_nolock(mapping);
265 }
266
268
269 (void)sem_post(&f_list->fl_sem);
270 return OK;
271}
272///重命名映射
273void rename_mapping(const char *src_path, const char *dst_path)
274{
275 int ret;
276 char *tmp = NULL;
277 int path_len;
278 struct file_map *fmap = NULL;
279 struct page_mapping *mapping = NULL;
280
281 if (src_path == NULL || dst_path == NULL) {
282 return;
283 }
284
285 path_len = strlen(dst_path);
286
287 /* protect the whole list in case of this node been deleted just after we found it */
288
289 (VOID)LOS_MuxLock(&g_file_mapping.lock, LOS_WAIT_FOREVER);
290
291 mapping = find_mapping_nolock(src_path);
292 if (!mapping) {
293 goto out;
294 }
295
296 fmap = LOS_DL_LIST_ENTRY(mapping, struct file_map, mapping);
297
298 tmp = LOS_MemAlloc(m_aucSysMem0, path_len + 1);
299 if (!tmp) {
300 PRINT_ERR("%s-%d: Mem alloc failed, path length(%d)\n", __FUNCTION__, __LINE__, path_len);
301 goto out;
302 }
303 ret = strncpy_s(tmp, path_len, dst_path, strlen(dst_path));
304 if (ret != 0) {
305 (VOID)LOS_MemFree(m_aucSysMem0, tmp);
306 goto out;
307 }
308
309 tmp[path_len] = '\0';
310 fmap->rename = tmp;
311
312out:
314}
315///更新文件路径
316int update_file_path(const char *old_path, const char *new_path)
317{
318 struct filelist *f_list = NULL;
319 struct file *filp = NULL;
320 int ret;
321
322 f_list = &tg_filelist;
323 ret = sem_wait(&f_list->fl_sem);
324 if (ret < 0) {
325 PRINTK("sem_wait error, ret=%d\n", ret);
326 return VFS_ERROR;
327 }
328
329 (VOID)LOS_MuxLock(&g_file_mapping.lock, LOS_WAIT_FOREVER);
330 for (int i = 3; i < CONFIG_NFILE_DESCRIPTORS; i++) {
331 if (!get_bit(i)) {
332 continue;
333 }
334 filp = &tg_filelist.fl_files[i];
335 if (filp->f_path == NULL || strcmp(filp->f_path, old_path)) {
336 continue;
337 }
338 int len = strlen(new_path) + 1;
339 char *tmp_path = LOS_MemAlloc(m_aucSysMem0, len);
340 if (tmp_path == NULL) {
341 PRINT_ERR("%s-%d: Mem alloc failed, path length(%d)\n", __FUNCTION__, __LINE__, len);
342 ret = VFS_ERROR;
343 goto out;
344 }
345 ret = strncpy_s(tmp_path, strlen(new_path) + 1, new_path, len);
346 if (ret != 0) {
347 (VOID)LOS_MemFree(m_aucSysMem0, tmp_path);
348 PRINT_ERR("%s-%d: strcpy failed.\n", __FUNCTION__, __LINE__);
349 ret = VFS_ERROR;
350 goto out;
351 }
352 free(filp->f_path);
353 filp->f_path = tmp_path;
354 }
355 ret = LOS_OK;
356
357out:
359 (void)sem_post(&f_list->fl_sem);
360 return ret;
361}
362
363#ifdef LOSCFG_DEBUG_VERSION
365{
366 return &g_file_mapping;
367}
368#endif
369#endif
STATIC INLINE VOID LOS_AtomicInc(Atomic *v)
Atomic addSelf.
Definition: los_atomic.h:253
STATIC INLINE INT32 LOS_AtomicRead(const Atomic *v)
Atomic read. | 读取32bit原子数据
Definition: los_atomic.h:123
STATIC INLINE VOID LOS_AtomicSet(Atomic *v, INT32 setVal)
Atomic setting.
Definition: los_atomic.h:147
STATIC INLINE VOID LOS_AtomicDec(Atomic *v)
Atomic auto-decrement. | 对32bit原子数据做减1
Definition: los_atomic.h:323
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListInit(LOS_DL_LIST *list)
Definition: los_list.h:104
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListTailInsert(LOS_DL_LIST *list, LOS_DL_LIST *node)
Insert a node to the tail of a doubly linked list.
Definition: los_list.h:244
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListDelete(LOS_DL_LIST *node)
Definition: los_list.h:292
VOID * LOS_MemAlloc(VOID *pool, UINT32 size)
从指定内存池中申请size长度的内存,注意这可不是从内核堆空间中申请内存
Definition: los_memory.c:1123
UINT32 LOS_MemFree(VOID *pool, VOID *ptr)
释放从指定动态内存中申请的内存
Definition: los_memory.c:1369
UINT8 * m_aucSysMem0
异常交互动态内存池地址的起始地址,当不支持异常交互特性时,m_aucSysMem0等于m_aucSysMem1。
Definition: los_memory.c:107
LITE_OS_SEC_TEXT UINT32 LOS_MuxInit(LosMux *mutex, const LosMuxAttr *attr)
初始化互斥锁
Definition: los_mux.c:262
LITE_OS_SEC_TEXT UINT32 LOS_MuxUnlock(LosMux *mutex)
释放锁
Definition: los_mux.c:559
LITE_OS_SEC_TEXT UINT32 LOS_MuxDestroy(LosMux *mutex)
销毁互斥锁
Definition: los_mux.c:289
LITE_OS_SEC_TEXT UINT32 LOS_MuxLock(LosMux *mutex, UINT32 timeout)
拿互斥锁,
Definition: los_mux.c:437
原子操作 http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-basic-atomic....
volatile INT32 Atomic
Definition: los_atomic.h:102
双向链表由内联函数实现 http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-apx-dll....
VOID LOS_SpinInit(SPIN_LOCK_S *lock)
Definition: los_spinlock.c:37
signed int INT32
Definition: los_typedef.h:60
int status_t
Definition: los_typedef.h:205
VOID OsFileCacheFlush(struct page_mapping *mapping)
文件缓存冲洗,把所有fpage冲洗一边,把脏页洗到dirtyList中,配合OsFileCacheRemove理解
VOID OsFileCacheRemove(struct page_mapping *mapping)
void * zalloc(size_t size)
Definition: malloc.c:91
void free(void *ptr)
释放ptr所指向的内存空间
Definition: malloc.c:66
int sem_post(sem_t *sem)
增加信号量计数
Definition: semaphore.c:139
int sem_wait(sem_t *sem)
获取信号量
Definition: semaphore.c:77
Definition: los_mux.h:73
struct page_mapping mapping
每个文件都有唯一的page_mapping标识其在内存的身份
char * owner
LOS_DL_LIST head
链表节点,用于挂到g_file_mapping上
loff_t f_pos
struct page_mapping * f_mapping
char * f_path
void * f_priv
unsigned long f_refcount
const char * f_relpath
int f_oflags
unsigned int f_magicnum
FAR struct inode * f_inode
void * f_dir
unsigned long nrpages
SPIN_LOCK_S list_lock
LOS_DL_LIST page_list
struct file * host
unsigned long flags
@note_why 全量代码中也没查到源码中对其操作
ARG_NUM_3 ARG_NUM_1 ARG_NUM_2 ARG_NUM_2 ARG_NUM_3 ARG_NUM_1 ARG_NUM_4 ARG_NUM_2 ARG_NUM_2 ARG_NUM_5 ARG_NUM_2 void
定义见于 third_party NuttX include nuttx fs fs h typedef volatile INT32 Atomic
void add_mapping(struct file *filep, const char *fullpath)
增加一个文件映射,这个函数被do_open()函数调用,每打开一次文件就会调用一次 注意不同的进程打开同一个文件,拿到的file是不一样的。 https://blog....
void dec_mapping_nolock(struct page_mapping *mapping)
无锁方式引用递减,删除或关闭文件时 由 files_close_internal调用
static struct page_mapping * find_mapping_nolock(const char *fullpath)
以无锁的方式通过文件名查找文件映射并返回
struct file_map * GetFileMappingList(void)
int update_file_path(const char *old_path, const char *new_path)
更新文件路径
void rename_mapping(const char *src_path, const char *dst_path)
重命名映射
static void clear_file_mapping(const struct page_mapping *mapping)
清除文件映射
int remove_mapping_nolock(struct page_mapping *mapping)
删除一个文件映射,需要有个三个地方删除才算断开了文件和内存的联系. 以无锁的方式删除映射
uint init_file_mapping()
int remove_mapping(const char *fullpath)
已有锁的方式删除文件映射
static struct file_map g_file_mapping
用于挂载所有文件的file_map