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

4.10
Last change on this file since b439daa was b439daa, checked in by Ralf Corsepius <ralf.corsepius@…>, on 06/17/10 at 03:48:39

2010-06-17 Ralf Corsépius <ralf.corsepius@…>

  • libfs/src/rfs/rtems-rfs-format.c: Various 64bit fixes.
  • Property mode set to 100644
File size: 17.7 KB
Line 
1/*
2 *  COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
3 *
4 *  The license and distribution terms for this file may be
5 *  found in the file LICENSE in this distribution or at
6 *  http://www.rtems.com/license/LICENSE.
7 *
8 *  $Id$
9 */
10/**
11 * @file
12 *
13 * @ingroup rtems-rfs
14 *
15 * RTEMS File Systems Format
16 *
17 * Format the file system ready for use.
18 */
19
20#if HAVE_CONFIG_H
21#include "config.h"
22#endif
23
24#include <stdlib.h>
25#include <stdio.h>
26#include <inttypes.h>
27
28#include <rtems/rfs/rtems-rfs-data.h>
29#include <rtems/rfs/rtems-rfs-file-system.h>
30#include <rtems/rfs/rtems-rfs-inode.h>
31#include <rtems/rtems-rfs-format.h>
32#include <rtems/rfs/rtems-rfs-dir.h>
33
34/**
35 * Return the number of gigabytes.
36 */
37#define GIGS(_g) (((uint64_t)(_g)) * 1024 * 1024)
38
39/**
40 * Return the number of bits that fit in the block size.
41 */
42static int
43rtems_rfs_bits_per_block (rtems_rfs_file_system* fs)
44{
45  return rtems_rfs_bitmap_numof_bits (rtems_rfs_fs_block_size (fs));
46}
47
48/**
49 * Return a rounded up integer quotient given a dividend and divisor. That is:
50 * "quotient = dividend / divisor"
51 */
52int
53rtems_rfs_rup_quotient (uint32_t dividend, uint32_t divisor)
54{
55  if (dividend == 0)
56    return 1;
57  return ((dividend - 1) / divisor) + 1;
58}
59
60/**
61 * Return the number of inodes as a percentage of the total number that can fit
62 * in a blocl.
63 */
64static int
65rtems_rfs_inodes_from_percent (rtems_rfs_file_system* fs,
66                               int                    percentage)
67{
68  int blocks;
69  blocks = ((rtems_rfs_fs_blocks (fs) -
70             RTEMS_RFS_SUPERBLOCK_SIZE) * percentage) / 100;
71  blocks = rtems_rfs_rup_quotient (blocks, fs->group_count);
72  return blocks * (rtems_rfs_fs_block_size (fs) / RTEMS_RFS_INODE_SIZE);
73}
74
75/**
76 * Return the inode overhead given a number of inodes.
77 */
78static int
79rtems_rfs_inode_overhead (rtems_rfs_file_system* fs)
80{
81  int blocks;
82  int bits_per_block;
83  blocks = rtems_rfs_rup_quotient(fs->group_inodes * RTEMS_RFS_INODE_SIZE,
84                                  rtems_rfs_fs_block_size (fs));
85  bits_per_block = rtems_rfs_bits_per_block (fs);
86  /*
87   * There could be more bits that there are blocks, eg 512K disk with 512
88   * blocks.
89   */
90  if (bits_per_block > (rtems_rfs_fs_blocks (fs) - RTEMS_RFS_SUPERBLOCK_SIZE))
91    bits_per_block = rtems_rfs_fs_blocks (fs) - RTEMS_RFS_SUPERBLOCK_SIZE;
92  return ((blocks + 1) * 100 * 10) / bits_per_block;
93}
94
95static bool
96rtems_rfs_check_config (rtems_rfs_file_system*         fs,
97                        const rtems_rfs_format_config* config)
98{
99  fs->block_size = config->block_size;
100  if (!fs->block_size)
101  {
102    uint64_t total_size = rtems_rfs_fs_media_size (fs);
103
104    if (total_size >= GIGS (1))
105    {
106      uint32_t gigs = (total_size + GIGS (1)) / GIGS (1);
107      int      b;
108      for (b = 31; b > 0; b--)
109        if ((gigs & (1 << b)) != 0)
110          break;
111      fs->block_size = 1 << b;
112    }
113
114    if (fs->block_size < 512)
115      fs->block_size = 512;
116   
117    if (fs->block_size > (4 * 1024))
118      fs->block_size = (4 * 1024);
119  }
120 
121  if ((fs->block_size % rtems_rfs_fs_media_block_size (fs)) != 0)
122  {
123    printf ("block size (%zd) is not a multiple of media block size (%" PRId32 ")\n",
124            fs->block_size, rtems_rfs_fs_media_block_size (fs));
125    return false;
126  }
127
128  fs->group_blocks = config->group_blocks;
129  if (!fs->group_blocks)
130  {
131    /*
132     * The number of blocks per group is defined by the number of bits in a
133     * block.
134     */
135    fs->group_blocks = rtems_rfs_bitmap_numof_bits (fs->block_size);
136  }
137
138  if (fs->group_blocks > rtems_rfs_bitmap_numof_bits (fs->block_size))
139  {
140    printf ("group block count is higher than bits in block\n");
141    return false;
142  }
143 
144  fs->blocks = rtems_rfs_fs_media_size (fs) / fs->block_size;
145
146  /*
147   * The bits per block sets the upper limit for the number of blocks in a
148   * group. The disk will be divided into groups which are the number of bits
149   * per block.
150   */ 
151  fs->group_count = rtems_rfs_rup_quotient (rtems_rfs_fs_blocks (fs),
152                                            rtems_rfs_bits_per_block (fs));
153
154  fs->group_inodes = config->group_inodes;
155  if (!fs->group_inodes)
156  {
157    int inode_overhead = RTEMS_RFS_INODE_OVERHEAD_PERCENTAGE;
158   
159    /*
160     * The number of inodes per group is set as a percentage.
161     */
162    if (config->inode_overhead)
163      inode_overhead = config->inode_overhead;
164     
165    fs->group_inodes = rtems_rfs_inodes_from_percent (fs, inode_overhead);
166  }
167
168  /*
169   * Round up to fill a block because the minimum allocation unit is a block.
170   */
171  fs->inodes_per_block = rtems_rfs_fs_block_size (fs) / RTEMS_RFS_INODE_SIZE;
172  fs->group_inodes =
173    rtems_rfs_rup_quotient (fs->group_inodes,
174                            fs->inodes_per_block) * fs->inodes_per_block;
175 
176  if (fs->group_inodes > rtems_rfs_bitmap_numof_bits (fs->block_size))
177    fs->group_inodes = rtems_rfs_bitmap_numof_bits (fs->block_size);
178
179  fs->max_name_length = config->max_name_length;
180  if (!fs->max_name_length)
181  {
182    fs->max_name_length = 512;
183  }
184 
185  return true;
186}
187
188static bool
189rtems_rfs_write_group (rtems_rfs_file_system* fs,
190                       int                    group,
191                       bool                   initialise_inodes,
192                       bool                   verbose)
193{
194  rtems_rfs_buffer_handle  handle;
195  rtems_rfs_bitmap_control bitmap;
196  rtems_rfs_buffer_block   group_base;
197  size_t                   group_size;
198  int                      blocks;
199  int                      b;
200  int                      rc;
201 
202  group_base = rtems_rfs_fs_block (fs, group, 0);
203
204  if (group_base > rtems_rfs_fs_blocks (fs))
205  {
206    printf ("rtems-rfs: write-group: group %d base beyond disk limit\n",
207            group);
208    return false;
209  }
210
211  group_size = fs->group_blocks;
212
213  /*
214   * Be nice to strange sizes of disks. These are embedded systems after all
215   * and nice numbers do not always work out. Let the last block pick up the
216   * remainder of the blocks.
217   */
218  if ((group_base + group_size) > rtems_rfs_fs_blocks (fs))
219    group_size = rtems_rfs_fs_blocks (fs) - group_base;
220
221  if (verbose)
222    printf ("\rrtems-rfs: format: group %3d: base = %" PRId32 ", size = %zd",
223            group, group_base, group_size);
224
225  /*
226   * Open a handle and request an empty buffer.
227   */
228  rc = rtems_rfs_buffer_handle_open (fs, &handle);
229  if (rc > 0)
230  {
231    printf ("\nrtems-rfs: write-group: handle open failed: %d: %s\n",
232            rc, strerror (rc));
233    return false;
234  }
235
236  if (verbose)
237    printf (", blocks");
238 
239  /*
240   * Open the block bitmap using the new buffer.
241   */
242  rc = rtems_rfs_bitmap_open (&bitmap, fs, &handle, group_size,
243                              group_base + RTEMS_RFS_GROUP_BLOCK_BITMAP_BLOCK);
244  if (rc > 0)
245  {
246    rtems_rfs_buffer_handle_close (fs, &handle);
247    printf ("\nrtems-rfs: write-group: group %3d: open block bitmap failed: %d: %s\n",
248            group, rc, strerror (rc));
249    return false;
250  }
251
252  /*
253   * Force the whole buffer to a known state. The bit map may not occupy the
254   * whole block.
255   */
256  memset (rtems_rfs_buffer_data (&handle), 0xff, rtems_rfs_fs_block_size (fs));
257 
258  /*
259   * Clear the bitmap.
260   */
261  rc = rtems_rfs_bitmap_map_clear_all (&bitmap);
262  if (rc > 0)
263  {
264    rtems_rfs_bitmap_close (&bitmap);
265    rtems_rfs_buffer_handle_close (fs, &handle);
266    printf ("\nrtems-rfs: write-group: group %3d: block bitmap clear all failed: %d: %s\n",
267            group, rc, strerror (rc));
268    return false;
269  }
270 
271  /*
272   * Forced allocation of the block bitmap.
273   */
274  rtems_rfs_bitmap_map_set (&bitmap, RTEMS_RFS_GROUP_BLOCK_BITMAP_BLOCK);
275
276  /*
277   * Forced allocation of the inode bitmap.
278   */
279  rtems_rfs_bitmap_map_set (&bitmap, RTEMS_RFS_GROUP_INODE_BITMAP_BLOCK);
280
281  /*
282   * Determine the number of inodes blocks in the group.
283   */
284  blocks = rtems_rfs_rup_quotient (fs->group_inodes, fs->inodes_per_block);
285
286  /*
287   * Forced allocation of the inode blocks which follow the block bitmap.
288   */
289  for (b = 0; b < blocks; b++)
290    rtems_rfs_bitmap_map_set (&bitmap, b + RTEMS_RFS_GROUP_INODE_BLOCK);
291
292  /*
293   * Close the block bitmap.
294   */
295  rc = rtems_rfs_bitmap_close (&bitmap);
296  if (rc > 0)
297  {
298    rtems_rfs_buffer_handle_close (fs, &handle);
299    printf ("\nrtems-rfs: write-group: group %3d: close block bitmap failed: %d: %s\n",
300            group, rc, strerror (rc));
301    return false;
302  }
303
304  rtems_rfs_buffer_mark_dirty (&handle);
305
306  if (verbose)
307    printf (", inodes");
308 
309  /*
310   * Open the inode bitmap using the old buffer. Should release any changes.
311   */
312  rc = rtems_rfs_bitmap_open (&bitmap, fs, &handle, group_size,
313                              group_base + RTEMS_RFS_GROUP_INODE_BITMAP_BLOCK);
314  if (rc > 0)
315  {
316    rtems_rfs_buffer_handle_close (fs, &handle);
317    printf ("\nrtems-rfs: write-group: group %3d: open inode bitmap failed: %d: %s\n",
318            group, rc, strerror (rc));
319    return false;
320  }
321
322  /*
323   * Force the whole buffer to a known state. The bit map may not occupy the
324   * whole block.
325   */
326  memset (rtems_rfs_buffer_data (&handle), 0x00, rtems_rfs_fs_block_size (fs));
327 
328  /*
329   * Clear the inode bitmap.
330   */
331  rc = rtems_rfs_bitmap_map_clear_all (&bitmap);
332  if (rc > 0)
333  {
334    rtems_rfs_bitmap_close (&bitmap);
335    rtems_rfs_buffer_handle_close (fs, &handle);
336    printf ("\nrtems-rfs: write-group: group %3d: inode bitmap" \
337            " clear all failed: %d: %s\n", group, rc, strerror (rc));
338    return false;
339  }
340 
341  /*
342   * Close the inode bitmap.
343   */
344  rc = rtems_rfs_bitmap_close (&bitmap);
345  if (rc > 0)
346  {
347    rtems_rfs_buffer_handle_close (fs, &handle);
348    printf ("\nrtems-rfs: write-group: group %3d: close inode" \
349            " bitmap failed: %d: %s\n", group, rc, strerror (rc));
350    return false;
351  }
352
353  rtems_rfs_buffer_mark_dirty (&handle);
354
355  /*
356   * Initialise the inode tables if rerquired to do so.
357   */
358  if (initialise_inodes)
359  {
360    for (b = 0; b < blocks; b++)
361    {
362      rc = rtems_rfs_buffer_handle_request (fs, &handle,
363                                            group_base + b + RTEMS_RFS_GROUP_INODE_BLOCK,
364                                            false);
365      if (rc > 0)
366      {
367        rtems_rfs_buffer_handle_close (fs, &handle);
368        printf ("\nrtems-rfs: write-group: group %3d: block %" PRId32 " request failed: %d: %s\n",
369                group, group_base + b + RTEMS_RFS_GROUP_INODE_BLOCK,
370                rc, strerror (rc));
371        return false;
372      }
373   
374      /*
375       * Force the whole buffer to a known state. The bit map may not occupy the
376       * whole block.
377       */
378      memset (rtems_rfs_buffer_data (&handle), 0xff, rtems_rfs_fs_block_size (fs));
379 
380      rtems_rfs_buffer_mark_dirty (&handle);
381    }
382  }
383 
384  rc = rtems_rfs_buffer_handle_close (fs, &handle);
385  if (rc > 0)
386  {
387    printf ("\nrtems-rfs: write-group: buffer handle close failed: %d: %s\n",
388            rc, strerror (rc));
389    return false;
390  }
391 
392  return true;
393}
394
395static bool
396rtems_rfs_write_superblock (rtems_rfs_file_system* fs)
397{
398  rtems_rfs_buffer_handle handle;
399  uint8_t*                sb;
400  int                     rc;
401
402  rc = rtems_rfs_buffer_handle_open (fs, &handle);
403  if (rc > 0)
404  {
405    printf ("rtems-rfs: write-superblock: handle open failed: %d: %s\n",
406            rc, strerror (rc));
407    return false;
408  }
409
410  rc = rtems_rfs_buffer_handle_request (fs, &handle, 0, false);
411  if (rc > 0)
412  {
413    rtems_rfs_buffer_handle_close (fs, &handle);
414    printf ("rtems-rfs: write-superblock: request failed: %d: %s\n",
415            rc, strerror (rc));
416    return false;
417  }
418
419  sb = rtems_rfs_buffer_data (&handle);
420 
421#define write_sb(_o, _d) rtems_rfs_write_u32(sb + (_o), _d)
422 
423  memset (sb, 0xff, rtems_rfs_fs_block_size (fs));
424
425  write_sb (RTEMS_RFS_SB_OFFSET_MAGIC, RTEMS_RFS_SB_MAGIC);
426  write_sb (RTEMS_RFS_SB_OFFSET_VERSION, RTEMS_RFS_VERSION);
427  write_sb (RTEMS_RFS_SB_OFFSET_BLOCKS, rtems_rfs_fs_blocks (fs));
428  write_sb (RTEMS_RFS_SB_OFFSET_BLOCK_SIZE, rtems_rfs_fs_block_size (fs));
429  write_sb (RTEMS_RFS_SB_OFFSET_BAD_BLOCKS, fs->bad_blocks);
430  write_sb (RTEMS_RFS_SB_OFFSET_MAX_NAME_LENGTH, fs->max_name_length);
431  write_sb (RTEMS_RFS_SB_OFFSET_GROUPS, fs->group_count);
432  write_sb (RTEMS_RFS_SB_OFFSET_GROUP_BLOCKS, fs->group_blocks);
433  write_sb (RTEMS_RFS_SB_OFFSET_GROUP_INODES, fs->group_inodes);
434  write_sb (RTEMS_RFS_SB_OFFSET_INODE_SIZE, RTEMS_RFS_INODE_SIZE);
435
436  rtems_rfs_buffer_mark_dirty (&handle);
437
438  rc = rtems_rfs_buffer_handle_release (fs, &handle);
439  if (rc > 0)
440  {
441    rtems_rfs_buffer_handle_close (fs, &handle);
442    printf ("rtems-rfs: write-superblock: buffer release failed: %d: %s\n",
443            rc, strerror (rc));
444    return false;
445  }
446
447  rc = rtems_rfs_buffer_handle_close (fs, &handle);
448  if (rc > 0)
449  {
450    printf ("rtems-rfs: write-superblock: buffer handle close failed: %d: %s\n",
451            rc, strerror (rc));
452    return false;
453  }
454 
455  return true;
456}
457
458static int
459rtems_rfs_write_root_dir (const char* name)
460{
461  rtems_rfs_file_system* fs;
462  rtems_rfs_inode_handle inode;
463  rtems_rfs_ino          ino;
464  int                    rc;
465
466  /*
467   * External API so returns -1.
468   */
469  rc = rtems_rfs_fs_open (name, NULL, RTEMS_RFS_FS_FORCE_OPEN, &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.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.