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

4.115
Last change on this file since d19c5352 was 7660e8b3, checked in by Sebastian Huber <sebastian.huber@…>, on 07/23/13 at 11:32:58

Include missing <string.h>

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