source: trunk/kernel/vfs/fatfs.c @ 8

Last change on this file since 8 was 1, checked in by alain, 8 years ago

First import

File size: 10.3 KB
RevLine 
[1]1/*
2 * fatfs.c - FATFS file system API implementation.
3 *
4 * Author    Mohamed Lamine Karaoui (2015)
5 *           Alain Greiner (2016)
6 *
7 * Copyright (c) UPMC Sorbonne Universites
8 *
9 * This file is part of ALMOS-MKH.
10 *
11 * ALMOS-MKH is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; version 2.0 of the License.
14 *
15 * ALMOS-MKH is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25
26#include <hal_types.h>
27#include <hal_special.h>
28#include <printk.h>
29#include <kmem.h>
30#include <ppm.h>
31#include <vfs.h>
32#include <rpc.h>
33#include <mapper.h>
34#include <dev_ioc.h>
35#include <fatfs.h>
36
37
38//////////////////////////////////////////////////////////////////////////////////////////
39//////////////////////////////////////////////////////////////////////////////////////////
40// FATFS specific functions : these functions cannot be called by the VFS
41//////////////////////////////////////////////////////////////////////////////////////////
42//////////////////////////////////////////////////////////////////////////////////////////
43
44//////////////////////////////////////////////////////////
45inline uint32_t fatfs_lba_from_cluster( fatfs_ctx_t * ctx,
46                                        uint32_t      cluster )
47{
48    return (ctx->cluster_begin_lba + ((cluster - 2) * ctx->sectors_per_cluster));
49}
50
51/////////////////////////////////////////////
52error_t fatfs_get_cluster( mapper_t * mapper,
53                           uint32_t   first_cluster,
54                           uint32_t   searched_page,
55                           uint32_t * cluster )
56{
57    page_t   * current_page_desc;      // pointer on current page descriptor
58    uint32_t * current_page_buffer;    // pointer on current page (array of uint32_t)
59    uint32_t   current_page_index;     // index of current page in mapper
60    uint32_t   current_page_offset;    // offset of slot in current page
61    uint32_t   page_count_in_file;     // index of page in file (index in linked list)
62    uint32_t   current_cluster;        // content of current FAT slot
63
64    // compute number of FAT slots per PPM page
65    uint32_t slots_per_page = CONFIG_PPM_PAGE_SIZE >> 2;
66
67    // initialize loop variable
68    current_page_index  = first_cluster / slots_per_page;
69    current_page_offset = first_cluster % slots_per_page;
70    page_count_in_file  = 0;
71
72    // scan FAT (i.e. traverse FAT linked list)
73    while( page_count_in_file <= searched_page )
74    {
75        // get pointer on current page descriptor
76        current_page_desc = mapper_get_page( mapper , current_page_index );
77
78        if( current_page_desc == NULL ) return EIO;
79
80        // get pointer on buffer for current page
81        current_page_buffer = (uint32_t *)ppm_page2base( current_page_desc );
82
83        // get FAT slot content
84        current_cluster = current_page_buffer[current_page_offset];
85
86        // update loop variables
87        current_page_index  = current_cluster / slots_per_page;
88        current_page_offset = current_cluster % slots_per_page;
89        page_count_in_file++;
90    }
91   
92    // return success
93    *cluster = current_cluster;
94    return 0;
95
96}  // end fatfs_get_cluster()
97
98
99////////////////////////////////////////////////////////////////////////////////////////
100// This function returns the FATFS cluster index of a page identified by its page
101// index in the file, using the FAT mapper. It scans the FAT mapper, starting from the
102// FATFS cluster index allocated to the first page of the file, until it reaches the
103// searched page. The FAT mapper is automatically updated in case of miss.
104// This function can be called by any thread running in any cluster, as it uses the
105// RPC_FATFS_GET_CLUSTER to access the remote FAT mapper if required.
106// We use a RPC to scan the FAT because the RPC_FIFO will avoid contention
107// in the cluster containing the FAT mapper, and the RPC latency is not critical
108// compared to the device access latency.
109////////////////////////////////////////////////////////////////////////////////////////
110// @ ctx               : pointer on local FATFS context.
111// @ first_cluster : first cluster allocated to a file in FATFS.
112// @ page_index    : index of searched page in file (one page occupies one cluster).
113// @ cluster_index : [out] pointer on buffer for FATFS cluster index.
114// @ return 0 if success / return EIO if a FAT cluster miss cannot be solved.
115////////////////////////////////////////////////////////////////////////////////////////
116static error_t fatfs_cluster_from_index( fatfs_ctx_t * ctx,
117                                         uint32_t      first_cluster,
118                                         uint32_t      page_index,
119                                         uint32_t    * cluster_index )
120{
121    uint32_t searched_cluster;   // searched FATFS cluster index
122    error_t  error;
123
124    // get extended pointer on FAT mapper
125    xptr_t fat_mapper_xp = ctx->fat_mapper_xp;
126
127    // get cluster cxy and local pointer on FAT mapper
128    cxy_t      fat_mapper_cxy = GET_CXY( fat_mapper_xp );
129    mapper_t * fat_mapper_ptr = (mapper_t *)GET_PTR( fat_mapper_xp );
130
131    if( fat_mapper_cxy == local_cxy )    // FAT mapper is local
132    {
133        error = fatfs_get_cluster( fat_mapper_ptr,
134                                   first_cluster,
135                                   page_index,
136                                   &searched_cluster );
137    }
138    else                                 // FAT mapper is remote
139    {
140        rpc_fatfs_get_cluster_client( fat_mapper_cxy,
141                                      fat_mapper_ptr,
142                                      first_cluster,
143                                      page_index,
144                                      &searched_cluster,
145                                      &error );
146    }
147   
148    if( error )
149    {
150        printk("\n[ERROR] in %s : cannot access FAT\n", __FUNCTION__ );
151        return error;
152    }
153
154    // return success
155    *cluster_index = searched_cluster;
156    return 0;
157
158}  // end fatfs_cluster_from_index()
159
160
161
162
163///////////////////////////////////////////////////////////////////////////////////////
164///////////////////////////////////////////////////////////////////////////////////////
165// Generic API : the following functions are called by the VFS,
166//               and must be defined by all isupported file systems.
167///////////////////////////////////////////////////////////////////////////////////////
168///////////////////////////////////////////////////////////////////////////////////////
169
170////////////////////////////////////////////////////////////
171error_t fatfs_inode_create( struct vfs_inode_s * vfs_inode )
172{
173    printk("\n[PANIC] %s not fully implemented yet\n", __FUNCTION__ );
174    hal_core_sleep();
175
176    kmem_req_t      req;
177    fatfs_inode_t * fatfs_inode;
178
179    // allocate memory for fatfs inode
180        req.type    = KMEM_FATFS_INODE;
181        req.size    = sizeof(fatfs_inode_t);
182    req.flags   = AF_KERNEL | AF_ZERO;
183        fatfs_inode = (fatfs_inode_t *)kmem_alloc( &req );
184
185    if( fatfs_inode == NULL ) return ENOMEM;
186
187    // initialise ramfs_inode
188    fatfs_inode->first_cluster = 0;   // TODO ???
189    fatfs_inode->ctx           = (fatfs_ctx_t *)vfs_inode->ctx->extend;
190 
191    // link fatfs_inode to vfs_inode
192    vfs_inode->extend = fatfs_inode;
193
194    return 0;
195
196}
197
198//////////////////////////////////////////////////////
199void fatfs_inode_destroy( struct vfs_inode_s * inode )
200{
201    printk("\n[PANIC] %s not fully implemented yet\n", __FUNCTION__ );
202    hal_core_sleep();
203}
204
205//////////////////////////////////////////////////
206error_t fatfs_ctx_create( struct vfs_ctx_s * ctx )
207{
208    printk("\n[PANIC] %s not fully implemented yet\n", __FUNCTION__ );
209    hal_core_sleep();
210
211    return 0;
212}
213
214////////////////////////////////////////////////
215void fatfs_ctx_destroy( struct vfs_ctx_s * ctx )
216{
217    printk("\n[PANIC] %s not fully implemented yet\n", __FUNCTION__ );
218    hal_core_sleep();
219}
220
221////////////////////////////////////////////////
222static error_t fatfs_access_page( page_t * page,
223                                  bool_t   is_read )
224{
225    // get source buffer base address
226    char * buffer = (char *)ppm_page2base( page );
227 
228    // get pointer on source mapper and page index from page descriptor
229    mapper_t * src_mapper  = page->mapper;
230    uint32_t   page_index  = page->index;
231
232    if( src_mapper == NULL)
233    {
234        printk("\n[PANIC] in %s : no mapper for this page\n", __FUNCTION__ );
235        hal_core_sleep();
236    }
237
238    // get VFS inode pointer from mapper
239    vfs_inode_t * vfs_inode = src_mapper->inode;
240
241    // get FATFS inode pointer for VFS inode
242    fatfs_inode_t * fatfs_inode = (fatfs_inode_t *)vfs_inode->extend;
243
244    // get first cluster index from FATFS inode
245    uint32_t  first_cluster = fatfs_inode->first_cluster;
246
247    // get FATFS context pointer from FATFS inode
248    fatfs_ctx_t * fatfs_ctx = fatfs_inode->ctx;
249
250    // get number of sectors
251    uint32_t count = fatfs_ctx->sectors_per_cluster;
252
253    // compute FATFS_cluster index for the accessed page
254    uint32_t cluster;
255    error_t  error = fatfs_cluster_from_index( fatfs_ctx,
256                                               first_cluster,
257                                               page_index,
258                                               &cluster );
259    if( error ) return EIO;
260
261    // get lba from cluster
262    uint32_t lba = fatfs_lba_from_cluster( fatfs_ctx , cluster );
263
264    // access device
265    if( is_read ) error = dev_ioc_read ( buffer , lba , count );
266    else          error = dev_ioc_write( buffer , lba , count );     
267
268    if( error )
269    {
270        printk("\n[ERROR] in %s : cannot access IOC device\n", __FUNCTION__ );
271        return error;
272    } 
273
274    // successful access
275    return 0;
276}
277
278////////////////////////////////////////////////
279error_t fatfs_write_page( struct page_s * page )
280{
281    bool_t is_read = false;
282    return fatfs_access_page( page , is_read );
283}
284
285///////////////////////////////////////////////
286error_t fatfs_read_page( struct page_s * page )
287{
288    bool_t is_read = true;
289    return fatfs_access_page( page , is_read );
290}
291
Note: See TracBrowser for help on using the repository browser.