source: rtems/cpukit/libcsupport/src/mount.c @ f08c7133

4.11
Last change on this file since f08c7133 was f08c7133, checked in by Sebastian Huber <sebastian.huber@…>, on 03/16/17 at 10:54:29

libio: Fix deadlock in location management

Perform a context-dependent deferred location release to avoid a
deadlock on the file system instance locks, for example during a
chdir().

Close #2936.

  • Property mode set to 100644
File size: 6.4 KB
Line 
1/**
2 *  @file
3 *
4 *  @brief Mounts a File System
5 *  @ingroup FileSystemTypesAndMount
6 */
7
8/*
9 *  COPYRIGHT (c) 1989-2010.
10 *  On-Line Applications Research Corporation (OAR).
11 *
12 *  Copyright (c) 2010-2012 embedded brains GmbH.
13 *
14 *  The license and distribution terms for this file may be
15 *  found in the file LICENSE in this distribution or at
16 *  http://www.rtems.org/license/LICENSE.
17 */
18
19#if HAVE_CONFIG_H
20  #include "config.h"
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25
26#include <rtems/libio_.h>
27
28RTEMS_CHAIN_DEFINE_EMPTY(rtems_filesystem_mount_table);
29
30const rtems_filesystem_limits_and_options_t rtems_filesystem_default_pathconf = {
31   5,    /* link_max: count */
32   128,  /* max_canon: max formatted input line size */
33   7,    /* max_input: max input line size */
34   255,  /* name_max: max name */
35   255,  /* path_max: max path */
36   1024, /* pipe_buf: pipe buffer size */
37   0,    /* posix_async_io: async IO supported on fs, 0=no, 1=yes */
38   0 ,   /* posix_chown_restrictions: can chown: 0=no, 1=yes */
39   1,    /* posix_no_trunc: error on filenames > max name, 0=no, 1=yes */
40   0,    /* posix_prio_io: priority IO, 0=no, 1=yes */
41   0,    /* posix_sync_io: file can be sync'ed, 0=no, 1=yes */
42   0     /* posix_vdisable: special char processing, 0=no, 1=yes */
43};
44
45static rtems_filesystem_mount_table_entry_t *alloc_mount_table_entry(
46  const char *source_or_null,
47  const char *target_or_null,
48  const char *filesystemtype,
49  size_t *target_length_ptr
50)
51{
52  const char *target = target_or_null != NULL ? target_or_null : "/";
53  size_t filesystemtype_size = strlen( filesystemtype ) + 1;
54  size_t source_size = source_or_null != NULL ?
55    strlen( source_or_null ) + 1 : 0;
56  size_t target_size = strlen( target ) + 1;
57  size_t size = sizeof( rtems_filesystem_mount_table_entry_t )
58    + filesystemtype_size + source_size + target_size
59    + sizeof( rtems_filesystem_global_location_t );
60  rtems_filesystem_mount_table_entry_t *mt_entry = calloc( 1, size );
61
62  if ( mt_entry != NULL ) {
63    rtems_filesystem_global_location_t *mt_fs_root =
64      (rtems_filesystem_global_location_t *)
65        ((char *) mt_entry + sizeof( *mt_entry ));
66    char *str = (char *) mt_fs_root + sizeof( *mt_fs_root );
67
68    memcpy( str, filesystemtype, filesystemtype_size );
69    mt_entry->type = str;
70    str += filesystemtype_size;
71
72    if ( source_or_null != NULL ) {
73      memcpy( str, source_or_null, source_size );
74      mt_entry->dev = str;
75      str += source_size;
76    }
77
78    memcpy( str, target, target_size );
79    mt_entry->target = str;
80
81    mt_entry->mounted = true;
82    mt_entry->mt_fs_root = mt_fs_root;
83    mt_entry->pathconf_limits_and_options = &rtems_filesystem_default_pathconf;
84
85    mt_fs_root->location.mt_entry = mt_entry;
86    mt_fs_root->reference_count = 1;
87
88    rtems_chain_initialize(
89      &mt_entry->location_chain,
90      mt_fs_root,
91      1,
92      sizeof(*mt_fs_root)
93    );
94  }
95
96  *target_length_ptr = target_size - 1;
97
98  return mt_entry;
99}
100
101static int register_subordinate_file_system(
102  rtems_filesystem_mount_table_entry_t *mt_entry,
103  const char *target
104)
105{
106  int rv = 0;
107  rtems_filesystem_eval_path_context_t ctx;
108  int eval_flags = RTEMS_FS_PERMS_RWX
109    | RTEMS_FS_FOLLOW_LINK;
110  rtems_filesystem_location_info_t *currentloc =
111    rtems_filesystem_eval_path_start( &ctx, target, eval_flags );
112
113  if ( !rtems_filesystem_location_is_instance_root( currentloc ) ) {
114    rtems_filesystem_location_info_t targetloc;
115    rtems_filesystem_global_location_t *mt_point_node;
116
117    rtems_filesystem_eval_path_extract_currentloc( &ctx, &targetloc );
118    mt_point_node = rtems_filesystem_location_transform_to_global( &targetloc );
119    mt_entry->mt_point_node = mt_point_node;
120    rv = (*mt_point_node->location.mt_entry->ops->mount_h)( mt_entry );
121    if ( rv == 0 ) {
122      rtems_filesystem_mt_lock();
123      rtems_chain_append_unprotected(
124        &rtems_filesystem_mount_table,
125        &mt_entry->mt_node
126      );
127      rtems_filesystem_mt_unlock();
128    } else {
129      rtems_filesystem_global_location_release( mt_point_node, true );
130    }
131  } else {
132    rtems_filesystem_eval_path_error( &ctx, EBUSY );
133    rv = -1;
134  }
135
136  rtems_filesystem_eval_path_cleanup( &ctx );
137
138  return rv;
139}
140
141static int register_root_file_system(
142  rtems_filesystem_mount_table_entry_t *mt_entry
143)
144{
145  int rv = 0;
146
147  rtems_filesystem_mt_lock();
148  if ( rtems_chain_is_empty( &rtems_filesystem_mount_table ) ) {
149    rtems_chain_append_unprotected(
150      &rtems_filesystem_mount_table,
151      &mt_entry->mt_node
152    );
153  } else {
154    errno = EINVAL;
155    rv = -1;
156  }
157  rtems_filesystem_mt_unlock();
158
159  if ( rv == 0 ) {
160    rtems_filesystem_global_location_t *new_fs_root =
161      rtems_filesystem_global_location_obtain( &mt_entry->mt_fs_root );
162    rtems_filesystem_global_location_t *new_fs_current =
163      rtems_filesystem_global_location_obtain( &mt_entry->mt_fs_root );
164
165    rtems_filesystem_global_location_assign(
166      &rtems_filesystem_root,
167      new_fs_root
168    );
169    rtems_filesystem_global_location_assign(
170      &rtems_filesystem_current,
171      new_fs_current
172    );
173  }
174
175  return rv;
176}
177
178int mount(
179  const char                 *source,
180  const char                 *target,
181  const char                 *filesystemtype,
182  rtems_filesystem_options_t options,
183  const void                 *data
184)
185{
186  int rv = 0;
187
188  if (
189    options == RTEMS_FILESYSTEM_READ_ONLY
190      || options == RTEMS_FILESYSTEM_READ_WRITE
191  ) {
192    rtems_filesystem_fsmount_me_t fsmount_me_h =
193      rtems_filesystem_get_mount_handler( filesystemtype );
194
195    if ( fsmount_me_h != NULL ) {
196      size_t target_length = 0;
197      rtems_filesystem_mount_table_entry_t *mt_entry = alloc_mount_table_entry(
198        source,
199        target,
200        filesystemtype,
201        &target_length
202      );
203
204      if ( mt_entry != NULL ) {
205        mt_entry->writeable = options == RTEMS_FILESYSTEM_READ_WRITE;
206
207        rv = (*fsmount_me_h)( mt_entry, data );
208        if ( rv == 0 ) {
209          if ( target != NULL ) {
210            rv = register_subordinate_file_system( mt_entry, target );
211          } else {
212            rv = register_root_file_system( mt_entry );
213          }
214
215          if ( rv != 0 ) {
216            (*mt_entry->ops->fsunmount_me_h)( mt_entry );
217          }
218        }
219
220        if ( rv != 0 ) {
221          free( mt_entry );
222        }
223      } else {
224        errno = ENOMEM;
225        rv = -1;
226      }
227    } else {
228      errno = EINVAL;
229      rv = -1;
230    }
231  } else {
232    errno = EINVAL;
233    rv = -1;
234  }
235
236  return rv;
237}
Note: See TracBrowser for help on using the repository browser.