source: rtems/cpukit/libblock/src/bdpart-write.c @ 3d60c1b

4.115
Last change on this file since 3d60c1b was 796967c, checked in by Sebastian Huber <sebastian.huber@…>, on 02/28/12 at 16:19:49

libblock: Change bdbuf API

The functions

o rtems_bdbuf_get(),
o rtems_bdbuf_read(),
o rtems_bdbuf_syncdev(), and
o rtems_bdbuf_purge_dev(),

use now the disk device instead of the device identifier. This makes
bdbuf independent of rtems_disk_obtain() and rtems_disk_release(). It
is the responsiblity of the file system to obtain the disk device. This
also reduces the overhead to get a buffer.

The key for the AVL tree uses now the disk device instead of the device
identifier. The pointer is interpreted as an unsigned integer. This
reduces the memory overhead and makes the comparison operation a bit
faster.

Removed function rtems_bdbuf_purge_major(). This function was too
destructive and could have unpredictable side effects.

  • Property mode set to 100644
File size: 7.6 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup rtems_bdpart
5 *
6 * Block device partition management.
7 */
8
9/*
10 * Copyright (c) 2009, 2010
11 * embedded brains GmbH
12 * Obere Lagerstr. 30
13 * D-82178 Puchheim
14 * Germany
15 * <rtems@embedded-brains.de>
16 *
17 * The license and distribution terms for this file may be
18 * found in the file LICENSE in this distribution or at
19 * http://www.rtems.com/license/LICENSE.
20 */
21
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
25
26#include <string.h>
27
28#include <rtems.h>
29#include <rtems/bdbuf.h>
30#include <rtems/bdpart.h>
31#include <rtems/endian.h>
32
33static void rtems_bdpart_write_mbr_partition(
34  uint8_t *data,
35  uint32_t begin,
36  uint32_t size,
37  uint8_t type,
38  uint8_t flags
39)
40{
41  rtems_uint32_to_little_endian( begin, data + RTEMS_BDPART_MBR_OFFSET_BEGIN);
42  rtems_uint32_to_little_endian( size, data + RTEMS_BDPART_MBR_OFFSET_SIZE);
43  data [RTEMS_BDPART_MBR_OFFSET_TYPE] = type;
44  data [RTEMS_BDPART_MBR_OFFSET_FLAGS] = flags;
45}
46
47static rtems_status_code rtems_bdpart_new_record(
48  const rtems_disk_device *dd,
49  rtems_blkdev_bnum index,
50  rtems_bdbuf_buffer **block
51)
52{
53  rtems_status_code sc = RTEMS_SUCCESSFUL;
54
55  /* Synchronize previous block if necessary */
56  if (*block != NULL) {
57    sc = rtems_bdbuf_sync( *block);
58    if (sc != RTEMS_SUCCESSFUL) {
59      return sc;
60    }
61  }
62
63  /* Read the new record block (this accounts for disk block sizes > 512) */
64  sc = rtems_bdbuf_read( dd, index, block);
65  if (sc != RTEMS_SUCCESSFUL) {
66    return sc;
67  }
68
69  /* just in case block did not get filled in */
70  if ( *block == NULL ) {
71    return RTEMS_INVALID_ADDRESS;
72  }
73
74  /* Clear record */
75  memset( (*block)->buffer, 0, RTEMS_BDPART_BLOCK_SIZE);
76
77  /* Write signature */
78  (*block)->buffer [RTEMS_BDPART_MBR_OFFSET_SIGNATURE_0] =
79    RTEMS_BDPART_MBR_SIGNATURE_0;
80  (*block)->buffer [RTEMS_BDPART_MBR_OFFSET_SIGNATURE_1] =
81    RTEMS_BDPART_MBR_SIGNATURE_1;
82
83  return RTEMS_SUCCESSFUL;
84}
85
86rtems_status_code rtems_bdpart_write(
87  const char *disk_name,
88  const rtems_bdpart_format *format,
89  const rtems_bdpart_partition *pt,
90  size_t count
91)
92{
93  rtems_status_code sc = RTEMS_SUCCESSFUL;
94  rtems_status_code esc = RTEMS_SUCCESSFUL;
95  bool dos_compatibility = format != NULL
96    && format->type == RTEMS_BDPART_FORMAT_MBR
97    && format->mbr.dos_compatibility;
98  rtems_bdbuf_buffer *block = NULL;
99  rtems_blkdev_bnum disk_end = 0;
100  rtems_blkdev_bnum record_space =
101    dos_compatibility ? RTEMS_BDPART_MBR_CYLINDER_SIZE : 1;
102  size_t ppc = 0; /* Primary partition count */
103  size_t i = 0;
104  uint8_t *data = NULL;
105  int fd = -1;
106  const rtems_disk_device *dd = NULL;
107
108  /* Check if we have something to do */
109  if (count == 0) {
110    /* Nothing to do */
111    return RTEMS_SUCCESSFUL;
112  }
113
114  /* Check parameter */
115  if (format == NULL || pt == NULL) {
116    return RTEMS_INVALID_ADDRESS;
117  }
118
119  /* Get disk data */
120  sc = rtems_bdpart_get_disk_data( disk_name, &fd, &dd, &disk_end);
121  if (sc != RTEMS_SUCCESSFUL) {
122    return sc;
123  }
124
125  /* Align end of disk on cylinder boundary if necessary */
126  if (dos_compatibility) {
127    disk_end -= (disk_end % record_space);
128  }
129
130  /* Check that we have a consistent partition table */
131  for (i = 0; i < count; ++i) {
132    const rtems_bdpart_partition *p = pt + i;
133
134    /* Check that begin and end are proper within the disk */
135    if (p->begin >= disk_end || p->end > disk_end) {
136      esc = RTEMS_INVALID_NUMBER;
137      goto cleanup;
138    }
139
140    /* Check that begin and end are valid */
141    if (p->begin >= p->end) {
142      esc = RTEMS_INVALID_NUMBER;
143      goto cleanup;
144    }
145
146    /* Check that partitions do not overlap */
147    if (i > 0 && pt [i - 1].end > p->begin) {
148      esc = RTEMS_INVALID_NUMBER;
149      goto cleanup;
150    }
151  }
152
153  /* Check format */
154  if (format->type != RTEMS_BDPART_FORMAT_MBR) {
155    esc = RTEMS_NOT_IMPLEMENTED;
156    goto cleanup;
157  }
158
159  /*
160   * Set primary partition count.  If we have more than four partitions we need
161   * an extended partition which will contain the partitions of number four and
162   * above as logical partitions.  If we have four or less partitions we can
163   * use the primary partition table.
164   */
165  ppc = count <= 4 ? count : 3;
166
167  /*
168   * Check that the first primary partition starts at head one and sector one
169   * under the virtual one head and 63 sectors geometry if necessary.
170   */
171  if (dos_compatibility && pt [0].begin != RTEMS_BDPART_MBR_CYLINDER_SIZE) {
172    esc = RTEMS_INVALID_NUMBER;
173    goto cleanup;
174  }
175
176  /*
177   * Check that we have enough space for the EBRs.  The partitions with number
178   * four and above are logical partitions if we have more than four partitions
179   * in total.  The logical partitions are contained in the extended partition.
180   * Each logical partition is described via one EBR preceding the partition.
181   * The space for the EBR and maybe some space which is needed for DOS
182   * compatibility resides between the partitions.  So there have to be gaps of
183   * the appropriate size between the partitions.
184   */
185  for (i = ppc; i < count; ++i) {
186    if ((pt [i].begin - pt [i - 1].end) < record_space) {
187      esc = RTEMS_INVALID_NUMBER;
188      goto cleanup;
189    }
190  }
191
192  /* Check that we can convert the parition descriptions to the MBR format */
193  for (i = 0; i < count; ++i) {
194    uint8_t type = 0;
195
196    const rtems_bdpart_partition *p = pt + i;
197
198    /* Check type */
199    if (!rtems_bdpart_to_mbr_partition_type( p->type, &type)) {
200      esc =  RTEMS_INVALID_ID;
201      goto cleanup;
202    }
203
204    /* Check flags */
205    if (p->flags > 0xffU) {
206      esc = RTEMS_INVALID_ID;
207      goto cleanup;
208    }
209
210    /* Check ID */
211    /* TODO */
212  }
213
214  /* New MBR */
215  sc = rtems_bdpart_new_record( dd, 0, &block);
216  if (sc != RTEMS_SUCCESSFUL) {
217    esc = sc;
218    goto cleanup;
219  }
220
221  /* Write disk ID */
222  rtems_uint32_to_little_endian(
223    format->mbr.disk_id,
224    block->buffer + RTEMS_BDPART_MBR_OFFSET_DISK_ID
225  );
226
227  /* Write primary partition table */
228  data = block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_0;
229  for (i = 0; i < ppc; ++i) {
230    const rtems_bdpart_partition *p = pt + i;
231
232    /* Write partition entry */
233    rtems_bdpart_write_mbr_partition(
234      data,
235      p->begin,
236      p->end - p->begin,
237      rtems_bdpart_mbr_partition_type( p->type),
238      (uint8_t) p->flags
239    );
240
241    data += RTEMS_BDPART_MBR_TABLE_ENTRY_SIZE;
242  }
243
244  /* Write extended partition with logical partitions if necessary */
245  if (ppc != count) {
246    rtems_blkdev_bnum ebr = 0; /* Extended boot record block index */
247
248    /* Begin of extended partition */
249    rtems_blkdev_bnum ep_begin = pt [ppc].begin - record_space;
250
251    /* Write extended partition */
252    rtems_bdpart_write_mbr_partition(
253      data,
254      ep_begin,
255      disk_end - ep_begin,
256      RTEMS_BDPART_MBR_EXTENDED,
257      0
258    );
259
260    /* Write logical partitions */
261    for (i = ppc; i < count; ++i) {
262      const rtems_bdpart_partition *p = pt + i;
263
264      /* Write second partition entry */
265      if (i > ppc) {
266        rtems_blkdev_bnum begin = p->begin - record_space;
267
268        rtems_bdpart_write_mbr_partition(
269          block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_1,
270          begin - ep_begin,
271          disk_end - begin,
272          RTEMS_BDPART_MBR_EXTENDED,
273          0
274        );
275      }
276
277      /* New EBR */
278      ebr = p->begin - record_space;
279      sc = rtems_bdpart_new_record( dd, ebr, &block);
280      if (sc != RTEMS_SUCCESSFUL) {
281        esc = sc;
282        goto cleanup;
283      }
284
285      /* Write first partition entry */
286      rtems_bdpart_write_mbr_partition(
287        block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_0,
288        record_space,
289        p->end - p->begin,
290        rtems_bdpart_mbr_partition_type( p->type),
291        (uint8_t) p->flags
292      );
293    }
294  }
295
296cleanup:
297
298  if (fd >= 0) {
299    close( fd);
300  }
301
302  if (block != NULL) {
303    rtems_bdbuf_sync( block);
304  }
305
306  return esc;
307}
Note: See TracBrowser for help on using the repository browser.