source: rtems/cpukit/posix/src/mmap.c @ c6023b7

5
Last change on this file since c6023b7 was c6023b7, checked in by Sebastian Huber <sebastian.huber@…>, on Oct 12, 2018 at 12:40:52 PM

posix: Fix unused result warning

  • Property mode set to 100644
File size: 8.0 KB
Line 
1/**
2 * @file
3 */
4
5/*
6 * Copyright (c) 2012 Chris Johns (chrisj@rtems.org)
7 * Copyright (c) 2017 Gedare Bloom (gedare@rtems.org)
8 * Copyright (c) 2017 Kevin kirspel (kirspkt@gmail.com)
9 *
10 * The license and distribution terms for this file may be
11 * found in the file LICENSE in this distribution or at
12 * http://www.rtems.org/license/LICENSE.
13 */
14
15#if HAVE_CONFIG_H
16#include "config.h"
17#endif
18
19#include <rtems.h>
20#include <errno.h>
21#include <stdlib.h>
22#include <string.h>
23#include <sys/mman.h>
24#include <sys/stat.h>
25#include <unistd.h>
26
27#include "rtems/libio_.h"
28
29#include <rtems/posix/mmanimpl.h>
30#include <rtems/posix/shmimpl.h>
31
32
33/**
34 * mmap chain of mappings.
35 */
36CHAIN_DEFINE_EMPTY( mmap_mappings );
37
38void *mmap(
39  void *addr, size_t len, int prot, int flags, int fildes, off_t off
40)
41{
42  struct stat     sb;
43  mmap_mapping   *mapping;
44  mmap_mapping   *current_mapping;
45  ssize_t         r;
46  rtems_libio_t  *iop;
47  bool            map_fixed;
48  bool            map_anonymous;
49  bool            map_shared;
50  bool            map_private;
51  bool            is_shared_shm;
52  int             err;
53
54  map_fixed = (flags & MAP_FIXED) == MAP_FIXED;
55  map_anonymous = (flags & MAP_ANON) == MAP_ANON;
56  map_shared = (flags & MAP_SHARED) == MAP_SHARED;
57  map_private = (flags & MAP_PRIVATE) == MAP_PRIVATE;
58
59  /* Clear errno. */
60  errno = 0;
61  iop = NULL;
62
63  if ( len == 0 ) {
64    errno = EINVAL;
65    return MAP_FAILED;
66  }
67
68  /*
69   * We can provide read, write and execute because the memory in RTEMS does
70   * not normally have protections but we cannot hide access to memory.
71   */
72  if ( prot == PROT_NONE ) {
73    errno = ENOTSUP;
74    return MAP_FAILED;
75  }
76
77  /*
78   * We can not normally provide restriction of write access. Reject any
79   * attempt to map without write permission, since we are not able to
80   * prevent a write from succeeding.
81   */
82  if ( PROT_WRITE != (prot & PROT_WRITE) ) {
83    errno = ENOTSUP;
84    return MAP_FAILED;
85  }
86
87  /*
88   * Anonymous mappings must have file descriptor set to -1 and the offset
89   * set to 0. Shared mappings are not supported with Anonymous mappings at
90   * this time
91   */
92  if ( map_anonymous && (fildes != -1 || off != 0 || map_shared) ) {
93    errno = EINVAL;
94    return MAP_FAILED;
95  }
96
97  /*
98   * If MAP_ANON is declared without MAP_PRIVATE or MAP_SHARED,
99   * force MAP_PRIVATE
100   */
101  if ( map_anonymous && !map_private && !map_shared ) {
102    flags |= MAP_PRIVATE;
103    map_private = true;
104  }
105
106  /* Check for supported flags */
107  if ((flags & ~(MAP_SHARED | MAP_PRIVATE | MAP_FIXED | MAP_ANON)) != 0) {
108    errno = EINVAL;
109    return MAP_FAILED;
110  }
111
112  /* Either MAP_SHARED or MAP_PRIVATE must be defined, but not both */
113  if ( map_shared ) {
114    if ( map_private ) {
115      errno = EINVAL;
116      return MAP_FAILED;
117    }
118  } else if ( !map_private ) {
119    errno = EINVAL;
120    return MAP_FAILED;
121  }
122
123  /* Check for illegal addresses. Watch out for address wrap. */
124  if ( map_fixed ) {
125    if ((uintptr_t)addr & PAGE_MASK) {
126      errno = EINVAL;
127      return MAP_FAILED;
128    }
129    if ( addr == NULL ) {
130      errno = EINVAL;
131      return MAP_FAILED;
132    }
133    if (addr + len < addr) {
134      errno = EINVAL;
135      return MAP_FAILED;
136    }
137  }
138
139  if ( !map_anonymous ) {
140    /*
141     * Get a stat of the file to get the dev + inode number and to make sure the
142     * fd is ok. The normal libio calls cannot be used because we need to return
143     * MAP_FAILED on error and they return -1 directly without coming back to
144     * here.
145     */
146    if ( fstat( fildes, &sb ) < 0 ) {
147      errno = EBADF;
148      return MAP_FAILED;
149    }
150
151    /* fstat ensures we have a good file descriptor. Hold on to iop. */
152    iop = rtems_libio_iop( fildes );
153
154    /* Check the type of file we have and make sure it is supported. */
155    if ( S_ISDIR( sb.st_mode ) || S_ISLNK( sb.st_mode )) {
156      errno = ENODEV;
157      return MAP_FAILED;
158    }
159
160    /* Check to see if the mapping is valid for a regular file. */
161    if ( S_ISREG( sb.st_mode )
162    /* FIXME: Should this be using strict inequality (>) comparisons? It would
163     * be valid to map a region exactly equal to the st_size, e.g. see below. */
164         && (( off >= sb.st_size ) || (( off + len ) >= sb.st_size ))) {
165      errno = EOVERFLOW;
166      return MAP_FAILED;
167    }
168
169    /* Check to see if the mapping is valid for other file/object types. */
170    if ( !S_ISCHR( sb.st_mode ) && sb.st_size < off + len ) {
171      errno = ENXIO;
172      return MAP_FAILED;
173    }
174
175    /* Do not seek on character devices, pipes, sockets, or memory objects. */
176    if ( S_ISREG( sb.st_mode ) || S_ISBLK( sb.st_mode ) ) {
177      if ( lseek( fildes, off, SEEK_SET ) < 0 ) {
178        return MAP_FAILED;
179      }
180    }
181
182    /* cdevs do not provide private mappings of any kind. */
183    if ( S_ISCHR( sb.st_mode ) && map_private ) {
184      errno = EINVAL;
185      return MAP_FAILED;
186    }
187  }
188
189  /* Create the mapping */
190  mapping = malloc( sizeof( mmap_mapping ));
191  if ( !mapping ) {
192    errno = ENOMEM;
193    return MAP_FAILED;
194  }
195  memset( mapping, 0, sizeof( mmap_mapping ));
196  mapping->len = len;
197  mapping->flags = flags;
198
199  if ( !map_anonymous ) {
200    /*
201     * HACK: We should have a better generic way to distinguish between
202     * shm objects and other mmap'd files. We need to know at munmap time
203     * if the mapping is to a shared memory object in order to refcnt shms.
204     * We could do this by providing mmap in the file operations if needed.
205     */
206    if ( S_ISREG( sb.st_mode ) || S_ISBLK( sb.st_mode ) ||
207         S_ISCHR( sb.st_mode ) || S_ISFIFO( sb.st_mode ) ||
208         S_ISSOCK( sb.st_mode ) ) {
209      is_shared_shm = false;
210    } else {
211      is_shared_shm = true;
212    }
213  } else {
214    is_shared_shm = false;
215  }
216
217  if ( map_fixed ) {
218    mapping->addr = addr;
219  } else if ( map_private ) {
220    /* private mappings of shared memory do not need special treatment. */
221    is_shared_shm = false;
222    err = posix_memalign( &mapping->addr, PAGE_SIZE, len );
223    if ( err != 0 ) {
224      free( mapping );
225      errno = ENOMEM;
226      return MAP_FAILED;
227    }
228  }
229
230  /* MAP_FIXED is not supported for shared memory objects with MAP_SHARED. */
231  if ( map_fixed && is_shared_shm ) {
232    free( mapping );
233    errno = ENOTSUP;
234    return MAP_FAILED;
235  }
236
237  mmap_mappings_lock_obtain();
238
239  if ( map_fixed ) {
240    rtems_chain_node* node = rtems_chain_first (&mmap_mappings);
241    while ( !rtems_chain_is_tail( &mmap_mappings, node )) {
242      /*
243       * If the map is fixed see if this address is already mapped. At this
244       * point in time if there is an overlap in the mappings we return an
245       * error. POSIX allows us to also return successfully by unmapping
246       * the overlapping prior mappings.
247       */
248      current_mapping = (mmap_mapping*) node;
249      if ( ( addr >= current_mapping->addr ) &&
250           ( addr < ( current_mapping->addr + current_mapping->len )) ) {
251        free( mapping );
252        mmap_mappings_lock_release( );
253        errno = ENXIO;
254        return MAP_FAILED;
255      }
256      node = rtems_chain_next( node );
257    }
258  }
259
260  /* Populate the data */
261  if ( map_private ) {
262    if ( !map_anonymous ) {
263      /*
264       * Use read() for private mappings. This updates atime as needed.
265       * Changes to the underlying object will NOT be reflected in the mapping.
266       * The underlying object can be removed while the mapping exists.
267       */
268      r = read( fildes, mapping->addr, len );
269
270      if ( r != len ) {
271        mmap_mappings_lock_release( );
272        if ( !map_fixed ) {
273          free( mapping->addr );
274        }
275        free( mapping );
276        errno = ENXIO;
277        return MAP_FAILED;
278      }
279    } else if ( !map_fixed ) {
280      memset( mapping->addr, 0, len );
281    }
282  } else if ( map_shared ) {
283    if ( is_shared_shm ) {
284      /* FIXME: This use of implementation details is a hack. */
285      mapping->shm = iop_to_shm( iop );
286    }
287
288    err = (*iop->pathinfo.handlers->mmap_h)(
289        iop, &mapping->addr, len, prot, off );
290    if ( err != 0 ) {
291      mmap_mappings_lock_release( );
292      free( mapping );
293      return MAP_FAILED;
294    }
295  }
296
297  rtems_chain_append_unprotected( &mmap_mappings, &mapping->node );
298
299  mmap_mappings_lock_release( );
300
301  return mapping->addr;
302}
Note: See TracBrowser for help on using the repository browser.