source: rtems/cpukit/libfs/src/rfs/rtems-rfs-format.c @ 562815c

4.115
Last change on this file since 562815c was ff1becb, checked in by Joel Sherrill <joel.sherrill@…>, on 01/10/13 at 19:22:57

rfs: Doxygen group cannot have a dash in it

Change rtems-rfs to rtems_rfs

  • Property mode set to 100644
File size: 17.8 KB
Line 
1/**
2 * @file
3 *
4 * @brief RTEMS File Systems Format
5 * @ingroup rtems_rfs
6 *
7 * Format the file system ready for use.
8 */
9
10/*
11 *  COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
12 *
13 *  The license and distribution terms for this file may be
14 *  found in the file LICENSE in this distribution or at
15 *  http://www.rtems.com/license/LICENSE.
16 */
17
18#if HAVE_CONFIG_H
19#include "config.h"
20#endif
21
22#include <stdlib.h>
23#include <stdio.h>
24#include <inttypes.h>
25
26#include <rtems/rfs/rtems-rfs-data.h>
27#include <rtems/rfs/rtems-rfs-file-system.h>
28#include <rtems/rfs/rtems-rfs-inode.h>
29#include <rtems/rtems-rfs-format.h>
30#include <rtems/rfs/rtems-rfs-dir.h>
31
32/**
33 * Return the number of gigabytes.
34 */
35#define GIGS(_g) (((uint64_t)(_g)) * 1024 * 1024)
36
37/**
38 * Return the number of bits that fit in the block size.
39 */
40static int
41rtems_rfs_bits_per_block (rtems_rfs_file_system* fs)
42{
43  return rtems_rfs_bitmap_numof_bits (rtems_rfs_fs_block_size (fs));
44}
45
46/**
47 * Return a rounded up integer quotient given a dividend and divisor. That is:
48 * "quotient = dividend / divisor"
49 */
50int
51rtems_rfs_rup_quotient (uint32_t dividend, uint32_t divisor)
52{
53  if (dividend == 0)
54    return 1;
55  return ((dividend - 1) / divisor) + 1;
56}
57
58/**
59 * Return the number of inodes as a percentage of the total number that can fit
60 * in a blocl.
61 */
62static int
63rtems_rfs_inodes_from_percent (rtems_rfs_file_system* fs,
64                               int                    percentage)
65{
66  int blocks;
67  blocks = ((rtems_rfs_fs_blocks (fs) -
68             RTEMS_RFS_SUPERBLOCK_SIZE) * percentage) / 100;
69  blocks = rtems_rfs_rup_quotient (blocks, fs->group_count);
70  return blocks * (rtems_rfs_fs_block_size (fs) / RTEMS_RFS_INODE_SIZE);
71}
72
73/**
74 * Return the inode overhead given a number of inodes.
75 */
76static int
77rtems_rfs_inode_overhead (rtems_rfs_file_system* fs)
78{
79  int blocks;
80  int bits_per_block;
81  blocks = rtems_rfs_rup_quotient(fs->group_inodes * RTEMS_RFS_INODE_SIZE,
82                                  rtems_rfs_fs_block_size (fs));
83  bits_per_block = rtems_rfs_bits_per_block (fs);
84  /*
85   * There could be more bits than blocks, eg 512K disk with 512 blocks.
86   */
87  if (bits_per_block > (rtems_rfs_fs_blocks (fs) - RTEMS_RFS_SUPERBLOCK_SIZE))
88    bits_per_block = rtems_rfs_fs_blocks (fs) - RTEMS_RFS_SUPERBLOCK_SIZE;
89  return ((blocks + 1) * 100 * 10) / bits_per_block;
90}
91
92static bool
93rtems_rfs_check_config (rtems_rfs_file_system*         fs,
94                        const rtems_rfs_format_config* config)
95{
96  fs->block_size = config->block_size;
97  if (!fs->block_size)
98  {
99    uint64_t total_size = rtems_rfs_fs_media_size (fs);
100
101    if (total_size >= GIGS (1))
102    {
103      uint32_t gigs = (total_size + GIGS (1)) / GIGS (1);
104      int      b;
105      for (b = 31; b > 0; b--)
106        if ((gigs & (1 << b)) != 0)
107          break;
108      fs->block_size = 1 << b;
109    }
110
111    if (fs->block_size < 512)
112      fs->block_size = 512;
113
114    if (fs->block_size > (4 * 1024))
115      fs->block_size = (4 * 1024);
116  }
117
118  if ((fs->block_size % rtems_rfs_fs_media_block_size (fs)) != 0)
119  {
120    printf ("block size (%zd) is not a multiple of media block size (%" PRId32 ")\n",
121            fs->block_size, rtems_rfs_fs_media_block_size (fs));
122    return false;
123  }
124
125  fs->group_blocks = config->group_blocks;
126  if (!fs->group_blocks)
127  {
128    /*
129     * The number of blocks per group is defined by the number of bits in a
130     * block.
131     */
132    fs->group_blocks = rtems_rfs_bitmap_numof_bits (fs->block_size);
133  }
134
135  if (fs->group_blocks > rtems_rfs_bitmap_numof_bits (fs->block_size))
136  {
137    printf ("group block count is higher than bits in block\n");
138    return false;
139  }
140
141  fs->blocks = rtems_rfs_fs_media_size (fs) / fs->block_size;
142
143  /*
144   * The bits per block sets the upper limit for the number of blocks in a
145   * group. The disk will be divided into groups which are the number of bits
146   * per block.
147   */
148  fs->group_count = rtems_rfs_rup_quotient (rtems_rfs_fs_blocks (fs),
149                                            rtems_rfs_bits_per_block (fs));
150
151  fs->group_inodes = config->group_inodes;
152  if (!fs->group_inodes)
153  {
154    int inode_overhead = RTEMS_RFS_INODE_OVERHEAD_PERCENTAGE;
155
156    /*
157     * The number of inodes per group is set as a percentage.
158     */
159    if (config->inode_overhead)
160      inode_overhead = config->inode_overhead;
161
162    fs->group_inodes = rtems_rfs_inodes_from_percent (fs, inode_overhead);
163  }
164
165  /*
166   * Round up to fill a block because the minimum allocation unit is a block.
167   */
168  fs->inodes_per_block = rtems_rfs_fs_block_size (fs) / RTEMS_RFS_INODE_SIZE;
169  fs->group_inodes =
170    rtems_rfs_rup_quotient (fs->group_inodes,
171                            fs->inodes_per_block) * fs->inodes_per_block;
172
173  if (fs->group_inodes > rtems_rfs_bitmap_numof_bits (fs->block_size))
174    fs->group_inodes = rtems_rfs_bitmap_numof_bits (fs->block_size);
175
176  fs->max_name_length = config->max_name_length;
177  if (!fs->max_name_length)
178  {
179    fs->max_name_length = 512;
180  }
181
182  return true;
183}
184
185static bool
186rtems_rfs_write_group (rtems_rfs_file_system* fs,
187                       int                    group,
188                       bool                   initialise_inodes,
189                       bool                   verbose)
190{
191  rtems_rfs_buffer_handle  handle;
192  rtems_rfs_bitmap_control bitmap;
193  rtems_rfs_buffer_block   group_base;
194  size_t                   group_size;
195  int                      blocks;
196  int                      b;
197  int                      rc;
198
199  group_base = rtems_rfs_fs_block (fs, group, 0);
200
201  if (group_base > rtems_rfs_fs_blocks (fs))
202  {
203    printf ("rtems-rfs: write-group: group %d base beyond disk limit\n",
204            group);
205    return false;
206  }
207
208  group_size = fs->group_blocks;
209
210  /*
211   * Be nice to strange sizes of disks. These are embedded systems after all
212   * and nice numbers do not always work out. Let the last block pick up the
213   * remainder of the blocks.
214   */
215  if ((group_base + group_size) > rtems_rfs_fs_blocks (fs))
216    group_size = rtems_rfs_fs_blocks (fs) - group_base;
217
218  if (verbose)
219    printf ("\rrtems-rfs: format: group %3d: base = %" PRId32 ", size = %zd",
220            group, group_base, group_size);
221
222  /*
223   * Open a handle and request an empty buffer.
224   */
225  rc = rtems_rfs_buffer_handle_open (fs, &handle);
226  if (rc > 0)
227  {
228    printf ("\nrtems-rfs: write-group: handle open failed: %d: %s\n",
229            rc, strerror (rc));
230    return false;
231  }
232
233  if (verbose)
234    printf (", blocks");
235
236  /*
237   * Open the block bitmap using the new buffer.
238   */
239  rc = rtems_rfs_bitmap_open (&bitmap, fs, &handle, group_size,
240                              group_base + RTEMS_RFS_GROUP_BLOCK_BITMAP_BLOCK);
241  if (rc > 0)
242  {
243    rtems_rfs_buffer_handle_close (fs, &handle);
244    printf ("\nrtems-rfs: write-group: group %3d: open block bitmap failed: %d: %s\n",
245            group, rc, strerror (rc));
246    return false;
247  }
248
249  /*
250   * Force the whole buffer to a known state. The bit map may not occupy the
251   * whole block.
252   */
253  memset (rtems_rfs_buffer_data (&handle), 0xff, rtems_rfs_fs_block_size (fs));
254
255  /*
256   * Clear the bitmap.
257   */
258  rc = rtems_rfs_bitmap_map_clear_all (&bitmap);
259  if (rc > 0)
260  {
261    rtems_rfs_bitmap_close (&bitmap);
262    rtems_rfs_buffer_handle_close (fs, &handle);
263    printf ("\nrtems-rfs: write-group: group %3d: block bitmap clear all failed: %d: %s\n",
264            group, rc, strerror (rc));
265    return false;
266  }
267
268  /*
269   * Forced allocation of the block bitmap.
270   */
271  rtems_rfs_bitmap_map_set (&bitmap, RTEMS_RFS_GROUP_BLOCK_BITMAP_BLOCK);
272
273  /*
274   * Forced allocation of the inode bitmap.
275   */
276  rtems_rfs_bitmap_map_set (&bitmap, RTEMS_RFS_GROUP_INODE_BITMAP_BLOCK);
277
278  /*
279   * Determine the number of inodes blocks in the group.
280   */
281  blocks = rtems_rfs_rup_quotient (fs->group_inodes, fs->inodes_per_block);
282
283  /*
284   * Forced allocation of the inode blocks which follow the block bitmap.
285   */
286  for (b = 0; b < blocks; b++)
287    rtems_rfs_bitmap_map_set (&bitmap, b + RTEMS_RFS_GROUP_INODE_BLOCK);
288
289  /*
290   * Close the block bitmap.
291   */
292  rc = rtems_rfs_bitmap_close (&bitmap);
293  if (rc > 0)
294  {
295    rtems_rfs_buffer_handle_close (fs, &handle);
296    printf ("\nrtems-rfs: write-group: group %3d: close block bitmap failed: %d: %s\n",
297            group, rc, strerror (rc));
298    return false;
299  }
300
301  rtems_rfs_buffer_mark_dirty (&handle);
302
303  if (verbose)
304    printf (", inodes");
305
306  /*
307   * Open the inode bitmap using the old buffer. Should release any changes.
308   */
309  rc = rtems_rfs_bitmap_open (&bitmap, fs, &handle, group_size,
310                              group_base + RTEMS_RFS_GROUP_INODE_BITMAP_BLOCK);
311  if (rc > 0)
312  {
313    rtems_rfs_buffer_handle_close (fs, &handle);
314    printf ("\nrtems-rfs: write-group: group %3d: open inode bitmap failed: %d: %s\n",
315            group, rc, strerror (rc));
316    return false;
317  }
318
319  /*
320   * Force the whole buffer to a known state. The bit map may not occupy the
321   * whole block.
322   */
323  memset (rtems_rfs_buffer_data (&handle), 0x00, rtems_rfs_fs_block_size (fs));
324
325  /*
326   * Clear the inode bitmap.
327   */
328  rc = rtems_rfs_bitmap_map_clear_all (&bitmap);
329  if (rc > 0)
330  {
331    rtems_rfs_bitmap_close (&bitmap);
332    rtems_rfs_buffer_handle_close (fs, &handle);
333    printf ("\nrtems-rfs: write-group: group %3d: inode bitmap" \
334            " clear all failed: %d: %s\n", group, rc, strerror (rc));
335    return false;
336  }
337
338  /*
339   * Close the inode bitmap.
340   */
341  rc = rtems_rfs_bitmap_close (&bitmap);
342  if (rc > 0)
343  {
344    rtems_rfs_buffer_handle_close (fs, &handle);
345    printf ("\nrtems-rfs: write-group: group %3d: close inode" \
346            " bitmap failed: %d: %s\n", group, rc, strerror (rc));
347    return false;
348  }
349
350  rtems_rfs_buffer_mark_dirty (&handle);
351
352  /*
353   * Initialise the inode tables if required to do so.
354   */
355  if (initialise_inodes)
356  {
357    for (b = 0; b < blocks; b++)
358    {
359      rc = rtems_rfs_buffer_handle_request (fs, &handle,
360                                            group_base + b + RTEMS_RFS_GROUP_INODE_BLOCK,
361                                            false);
362      if (rc > 0)
363      {
364        rtems_rfs_buffer_handle_close (fs, &handle);
365        printf ("\nrtems-rfs: write-group: group %3d: block %" PRId32 " request failed: %d: %s\n",
366                group, group_base + b + RTEMS_RFS_GROUP_INODE_BLOCK,
367                rc, strerror (rc));
368        return false;
369      }
370
371      /*
372       * Force the whole buffer to a known state. The bit map may not occupy the
373       * whole block.
374       */
375      memset (rtems_rfs_buffer_data (&handle), 0xff, rtems_rfs_fs_block_size (fs));
376
377      rtems_rfs_buffer_mark_dirty (&handle);
378    }
379  }
380
381  rc = rtems_rfs_buffer_handle_close (fs, &handle);
382  if (rc > 0)
383  {
384    printf ("\nrtems-rfs: write-group: buffer handle close failed: %d: %s\n",
385            rc, strerror (rc));
386    return false;
387  }
388
389  return true;
390}
391
392static bool
393rtems_rfs_write_superblock (rtems_rfs_file_system* fs)
394{
395  rtems_rfs_buffer_handle handle;
396  uint8_t*                sb;
397  int                     rc;
398
399  rc = rtems_rfs_buffer_handle_open (fs, &handle);
400  if (rc > 0)
401  {
402    printf ("rtems-rfs: write-superblock: handle open failed: %d: %s\n",
403            rc, strerror (rc));
404    return false;
405  }
406
407  rc = rtems_rfs_buffer_handle_request (fs, &handle, 0, false);
408  if (rc > 0)
409  {
410    rtems_rfs_buffer_handle_close (fs, &handle);
411    printf ("rtems-rfs: write-superblock: request failed: %d: %s\n",
412            rc, strerror (rc));
413    return false;
414  }
415
416  sb = rtems_rfs_buffer_data (&handle);
417
418#define write_sb(_o, _d) rtems_rfs_write_u32(sb + (_o), _d)
419
420  memset (sb, 0xff, rtems_rfs_fs_block_size (fs));
421
422  write_sb (RTEMS_RFS_SB_OFFSET_MAGIC, RTEMS_RFS_SB_MAGIC);
423  write_sb (RTEMS_RFS_SB_OFFSET_VERSION, RTEMS_RFS_VERSION);
424  write_sb (RTEMS_RFS_SB_OFFSET_BLOCKS, rtems_rfs_fs_blocks (fs));
425  write_sb (RTEMS_RFS_SB_OFFSET_BLOCK_SIZE, rtems_rfs_fs_block_size (fs));
426  write_sb (RTEMS_RFS_SB_OFFSET_BAD_BLOCKS, fs->bad_blocks);
427  write_sb (RTEMS_RFS_SB_OFFSET_MAX_NAME_LENGTH, fs->max_name_length);
428  write_sb (RTEMS_RFS_SB_OFFSET_GROUPS, fs->group_count);
429  write_sb (RTEMS_RFS_SB_OFFSET_GROUP_BLOCKS, fs->group_blocks);
430  write_sb (RTEMS_RFS_SB_OFFSET_GROUP_INODES, fs->group_inodes);
431  write_sb (RTEMS_RFS_SB_OFFSET_INODE_SIZE, RTEMS_RFS_INODE_SIZE);
432
433  rtems_rfs_buffer_mark_dirty (&handle);
434
435  rc = rtems_rfs_buffer_handle_release (fs, &handle);
436  if (rc > 0)
437  {
438    rtems_rfs_buffer_handle_close (fs, &handle);
439    printf ("rtems-rfs: write-superblock: buffer release failed: %d: %s\n",
440            rc, strerror (rc));
441    return false;
442  }
443
444  rc = rtems_rfs_buffer_handle_close (fs, &handle);
445  if (rc > 0)
446  {
447    printf ("rtems-rfs: write-superblock: buffer handle close failed: %d: %s\n",
448            rc, strerror (rc));
449    return false;
450  }
451
452  return true;
453}
454
455static int
456rtems_rfs_write_root_dir (const char* name)
457{
458  rtems_rfs_file_system* fs;
459  rtems_rfs_inode_handle inode;
460  rtems_rfs_ino          ino;
461  int                    rc;
462
463  /*
464   * External API so returns -1.
465   */
466  rc = rtems_rfs_fs_open (name, NULL,
467                          RTEMS_RFS_FS_FORCE_OPEN | RTEMS_RFS_FS_NO_LOCAL_CACHE,
468                          0, &fs);
469  if (rc < 0)
470  {
471    printf ("rtems-rfs: format: file system open failed: %d: %s\n",
472            errno, strerror (errno));
473    return -1;
474  }
475
476  rc = rtems_rfs_inode_alloc (fs, RTEMS_RFS_ROOT_INO, &ino);
477  if (rc > 0)
478  {
479    printf ("rtems-rfs: format: inode allocation failed: %d: %s\n",
480            rc, strerror (rc));
481    rtems_rfs_fs_close (fs);
482    return rc;
483  }
484
485  if (ino != RTEMS_RFS_ROOT_INO)
486  {
487    printf ("rtems-rfs: format: allocated inode not root ino: %" PRId32 "\n", ino);
488    rtems_rfs_fs_close (fs);
489    return rc;
490  }
491
492  rc = rtems_rfs_inode_open (fs, ino, &inode, true);
493  if (rc > 0)
494  {
495    printf ("rtems-rfs: format: inode open failed: %d: %s\n",
496            rc, strerror (rc));
497    rtems_rfs_group_bitmap_free (fs, true, ino);
498    rtems_rfs_fs_close (fs);
499    return rc;
500  }
501
502  rc = rtems_rfs_inode_initialise (&inode, 0,
503                                   (RTEMS_RFS_S_IFDIR | RTEMS_RFS_S_IRWXU |
504                                    RTEMS_RFS_S_IXGRP | RTEMS_RFS_S_IXOTH),
505                                   0, 0);
506  if (rc > 0)
507    printf ("rtems-rfs: format: inode initialise failed: %d: %s\n",
508            rc, strerror (rc));
509
510  rc = rtems_rfs_dir_add_entry (fs, &inode, ".", 1, ino);
511  if (rc > 0)
512    printf ("rtems-rfs: format: directory add failed: %d: %s\n",
513            rc, strerror (rc));
514
515  rc = rtems_rfs_inode_close (fs, &inode);
516  if (rc > 0)
517    printf ("rtems-rfs: format: inode close failed: %d: %s\n",
518            rc, strerror (rc));
519
520  rc = rtems_rfs_fs_close (fs);
521  if (rc < 0)
522    printf ("rtems-rfs: format: file system close failed: %d: %s\n",
523            errno, strerror (errno));
524
525  return rc;
526}
527
528int
529rtems_rfs_format (const char* name, const rtems_rfs_format_config* config)
530{
531  rtems_rfs_file_system fs;
532  int                   group;
533  int                   rc;
534
535  if (config->verbose)
536    printf ("rtems-rfs: format: %s\n", name);
537
538  memset (&fs, 0, sizeof (rtems_rfs_file_system));
539
540  rtems_chain_initialize_empty (&fs.buffers);
541  rtems_chain_initialize_empty (&fs.release);
542  rtems_chain_initialize_empty (&fs.release_modified);
543  rtems_chain_initialize_empty (&fs.file_shares);
544
545  fs.max_held_buffers = RTEMS_RFS_FS_MAX_HELD_BUFFERS;
546
547  fs.release_count = 0;
548  fs.release_modified_count = 0;
549
550  fs.flags = RTEMS_RFS_FS_NO_LOCAL_CACHE;
551
552  /*
553   * Open the buffer interface.
554   */
555  rc = rtems_rfs_buffer_open (name, &fs);
556  if (rc > 0)
557  {
558    printf ("rtems-rfs: format: buffer open failed: %d: %s\n",
559            rc, strerror (rc));
560    return -1;
561  }
562
563  /*
564   * Check the media.
565   */
566  if (rtems_rfs_fs_media_block_size (&fs) == 0)
567  {
568    printf ("rtems-rfs: media block is invalid: %" PRIu32 "\n",
569            rtems_rfs_fs_media_block_size (&fs));
570    return -1;
571  }
572
573  /*
574   * Check the configuration data.
575   */
576  if (!rtems_rfs_check_config (&fs, config))
577    return -1;
578
579  if (config->verbose)
580  {
581    printf ("rtems-rfs: format: media size = %" PRIu64 "\n",
582            rtems_rfs_fs_media_size (&fs));
583    printf ("rtems-rfs: format: media blocks = %" PRIu32 "\n",
584            rtems_rfs_fs_media_blocks (&fs));
585    printf ("rtems-rfs: format: media block size = %" PRIu32 "\n",
586            rtems_rfs_fs_media_block_size (&fs));
587    printf ("rtems-rfs: format: size = %" PRIu64 "\n",
588            rtems_rfs_fs_size (&fs));
589    printf ("rtems-rfs: format: blocks = %zu\n",
590            rtems_rfs_fs_blocks (&fs));
591    printf ("rtems-rfs: format: block size = %zu\n",
592            rtems_rfs_fs_block_size (&fs));
593    printf ("rtems-rfs: format: bits per block = %u\n",
594            rtems_rfs_bits_per_block (&fs));
595    printf ("rtems-rfs: format: inode size = %zu\n", RTEMS_RFS_INODE_SIZE);
596    printf ("rtems-rfs: format: inodes = %zu (%d.%d%%)\n",
597            fs.group_inodes * fs.group_count,
598            rtems_rfs_inode_overhead (&fs) / 10,
599            rtems_rfs_inode_overhead (&fs) % 10);
600    printf ("rtems-rfs: format: groups = %u\n", fs.group_count);
601    printf ("rtems-rfs: format: group blocks = %zu\n", fs.group_blocks);
602    printf ("rtems-rfs: format: group inodes = %zu\n", fs.group_inodes);
603  }
604
605  rc = rtems_rfs_buffer_setblksize (&fs, rtems_rfs_fs_block_size (&fs));
606  if (rc > 0)
607  {
608    printf ("rtems-rfs: format: setting block size failed: %d: %s\n",
609            rc, strerror (rc));
610    return -1;
611  }
612
613  if (!rtems_rfs_write_superblock (&fs))
614  {
615    printf ("rtems-rfs: format: superblock write failed\n");
616    return -1;
617  }
618
619  for (group = 0; group < fs.group_count; group++)
620    if (!rtems_rfs_write_group (&fs, group,
621                                config->initialise_inodes, config->verbose))
622      return -1;
623
624  if (config->verbose)
625    printf ("\n");
626
627  rc = rtems_rfs_buffer_close (&fs);
628  if (rc > 0)
629  {
630    printf ("rtems-rfs: format: buffer close failed: %d: %s\n",
631            rc, strerror (rc));
632    return -1;
633  }
634
635  rc = rtems_rfs_write_root_dir (name);
636  if (rc > 0)
637  {
638    printf ("rtems-rfs: format: writing root dir failed: %d: %s\n",
639            rc, strerror (rc));
640    return -1;
641  }
642
643  return 0;
644}
Note: See TracBrowser for help on using the repository browser.