Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:15

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  *  @file
0005  *
0006  *  @brief RTEMS File System Location Support
0007  *  @ingroup LibIOInternal
0008  */
0009 
0010 /*
0011  * Copyright (C) 2012, 2015 embedded brains GmbH & Co. KG
0012  *
0013  * Redistribution and use in source and binary forms, with or without
0014  * modification, are permitted provided that the following conditions
0015  * are met:
0016  * 1. Redistributions of source code must retain the above copyright
0017  *    notice, this list of conditions and the following disclaimer.
0018  * 2. Redistributions in binary form must reproduce the above copyright
0019  *    notice, this list of conditions and the following disclaimer in the
0020  *    documentation and/or other materials provided with the distribution.
0021  *
0022  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0023  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0024  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0025  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0026  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0027  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0028  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0029  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0030  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0031  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0032  * POSSIBILITY OF SUCH DAMAGE.
0033  */
0034 
0035 #ifdef HAVE_CONFIG_H
0036 #include "config.h"
0037 #endif
0038 
0039 #include <stdlib.h>
0040 
0041 #include <rtems/libio_.h>
0042 
0043 rtems_interrupt_lock rtems_filesystem_mt_entry_lock_control =
0044   RTEMS_INTERRUPT_LOCK_INITIALIZER("mount table entry");
0045 
0046 RTEMS_INTERRUPT_LOCK_DEFINE(
0047   static,
0048   deferred_release_lock,
0049   "Filesystem Deferred Release"
0050 )
0051 
0052 static rtems_filesystem_global_location_t *deferred_released_global_locations;
0053 
0054 rtems_filesystem_location_info_t *rtems_filesystem_location_copy(
0055   rtems_filesystem_location_info_t *dst,
0056   const rtems_filesystem_location_info_t *src
0057 )
0058 {
0059   dst->node_access = src->node_access;
0060   dst->node_access_2 = src->node_access_2;
0061   dst->handlers = src->handlers;
0062   dst->mt_entry = src->mt_entry;
0063   rtems_chain_initialize_node(&dst->mt_entry_node);
0064   rtems_filesystem_location_add_to_mt_entry(dst);
0065 
0066   return dst;
0067 }
0068 
0069 void rtems_filesystem_location_detach(
0070   rtems_filesystem_location_info_t *detach
0071 )
0072 {
0073   rtems_filesystem_location_free(detach);
0074   rtems_filesystem_location_initialize_to_null(detach);
0075 }
0076 
0077 void rtems_filesystem_location_copy_and_detach(
0078   rtems_filesystem_location_info_t *copy,
0079   rtems_filesystem_location_info_t *detach
0080 )
0081 {
0082   rtems_filesystem_location_copy(copy, detach);
0083   rtems_filesystem_location_remove_from_mt_entry(detach);
0084   rtems_filesystem_location_initialize_to_null(detach);
0085 }
0086 
0087 rtems_filesystem_global_location_t *rtems_filesystem_location_transform_to_global(
0088   rtems_filesystem_location_info_t *loc
0089 )
0090 {
0091   rtems_filesystem_global_location_t *global_loc = malloc(sizeof(*global_loc));
0092 
0093   if (global_loc != NULL) {
0094     global_loc->reference_count = 1;
0095     global_loc->deferred_released_next = NULL;
0096     global_loc->deferred_released_count = 0;
0097     rtems_filesystem_location_copy(&global_loc->location, loc);
0098     rtems_filesystem_location_remove_from_mt_entry(loc);
0099   } else {
0100     rtems_filesystem_location_free(loc);
0101     global_loc = rtems_filesystem_global_location_obtain_null();
0102     errno = ENOMEM;
0103   }
0104 
0105   return global_loc;
0106 }
0107 
0108 void rtems_filesystem_global_location_assign(
0109   rtems_filesystem_global_location_t **lhs_global_loc_ptr,
0110   rtems_filesystem_global_location_t *rhs_global_loc
0111 )
0112 {
0113   rtems_filesystem_mt_entry_declare_lock_context(lock_context);
0114   rtems_filesystem_global_location_t *lhs_global_loc;
0115 
0116   rtems_filesystem_mt_entry_lock(lock_context);
0117   lhs_global_loc = *lhs_global_loc_ptr;
0118   *lhs_global_loc_ptr = rhs_global_loc;
0119   rtems_filesystem_mt_entry_unlock(lock_context);
0120 
0121   rtems_filesystem_global_location_release(lhs_global_loc, true);
0122 }
0123 
0124 static void release_with_count(
0125   rtems_filesystem_global_location_t *global_loc,
0126   int count
0127 )
0128 {
0129   rtems_filesystem_mount_table_entry_t *mt_entry =
0130     global_loc->location.mt_entry;
0131   rtems_filesystem_mt_entry_declare_lock_context(lock_context);
0132   bool do_free;
0133   bool do_unmount;
0134 
0135   rtems_filesystem_mt_entry_lock(lock_context);
0136   global_loc->reference_count -= count;
0137   do_free = global_loc->reference_count == 0;
0138   do_unmount = rtems_filesystem_is_ready_for_unmount(mt_entry);
0139   rtems_filesystem_mt_entry_unlock(lock_context);
0140 
0141   if (do_free) {
0142     rtems_filesystem_location_free(&global_loc->location);
0143     free(global_loc);
0144   }
0145 
0146   if (do_unmount) {
0147     rtems_filesystem_do_unmount(mt_entry);
0148   }
0149 }
0150 
0151 static void deferred_release(void)
0152 {
0153   rtems_filesystem_global_location_t *current = NULL;
0154 
0155   do {
0156     rtems_interrupt_lock_context lock_context;
0157     int count = 0;
0158 
0159     rtems_interrupt_lock_acquire(&deferred_release_lock, &lock_context);
0160     current = deferred_released_global_locations;
0161     if (current != NULL) {
0162       deferred_released_global_locations = current->deferred_released_next;
0163       count = current->deferred_released_count;
0164       current->deferred_released_next = NULL;
0165       current->deferred_released_count = 0;
0166     }
0167     rtems_interrupt_lock_release(&deferred_release_lock, &lock_context);
0168 
0169     if (current != NULL) {
0170       release_with_count(current, count);
0171     }
0172   } while (current != NULL);
0173 }
0174 
0175 rtems_filesystem_global_location_t *rtems_filesystem_global_location_obtain(
0176   rtems_filesystem_global_location_t *const *global_loc_ptr
0177 )
0178 {
0179   rtems_filesystem_mt_entry_declare_lock_context(lock_context);
0180   rtems_filesystem_global_location_t *global_loc;
0181 
0182   if (deferred_released_global_locations != NULL) {
0183     deferred_release();
0184   }
0185 
0186   rtems_filesystem_mt_entry_lock(lock_context);
0187   global_loc = *global_loc_ptr;
0188   if (global_loc == NULL || !global_loc->location.mt_entry->mounted) {
0189     global_loc = &rtems_filesystem_global_location_null;
0190     errno = ENXIO;
0191   }
0192   ++global_loc->reference_count;
0193   rtems_filesystem_mt_entry_unlock(lock_context);
0194 
0195   return global_loc;
0196 }
0197 
0198 void rtems_filesystem_global_location_release(
0199   rtems_filesystem_global_location_t *global_loc,
0200   bool deferred
0201 )
0202 {
0203   if (!deferred) {
0204     release_with_count(global_loc, 1);
0205   } else {
0206     rtems_interrupt_lock_context lock_context;
0207 
0208     rtems_interrupt_lock_acquire(&deferred_release_lock, &lock_context);
0209 
0210     if (global_loc->deferred_released_count == 0) {
0211       rtems_filesystem_global_location_t *head =
0212         deferred_released_global_locations;
0213 
0214       global_loc->deferred_released_count = 1;
0215       global_loc->deferred_released_next = head;
0216       deferred_released_global_locations = global_loc;
0217     } else {
0218       ++global_loc->deferred_released_count;
0219     }
0220 
0221     rtems_interrupt_lock_release(&deferred_release_lock, &lock_context);
0222   }
0223 }
0224 
0225 void rtems_filesystem_location_remove_from_mt_entry(
0226   rtems_filesystem_location_info_t *loc
0227 )
0228 {
0229   rtems_filesystem_mt_entry_declare_lock_context(lock_context);
0230   bool do_unmount;
0231 
0232   rtems_filesystem_mt_entry_lock(lock_context);
0233   rtems_chain_extract_unprotected(&loc->mt_entry_node);
0234   do_unmount = rtems_filesystem_is_ready_for_unmount(loc->mt_entry);
0235   rtems_filesystem_mt_entry_unlock(lock_context);
0236 
0237   if (do_unmount) {
0238     rtems_filesystem_do_unmount(loc->mt_entry);
0239   }
0240 }
0241 
0242 void rtems_filesystem_do_unmount(
0243   rtems_filesystem_mount_table_entry_t *mt_entry
0244 )
0245 {
0246   rtems_filesystem_mt_lock();
0247   rtems_chain_extract_unprotected(&mt_entry->mt_node);
0248   rtems_filesystem_mt_unlock();
0249   rtems_filesystem_global_location_release(mt_entry->mt_point_node, false);
0250   (*mt_entry->ops->fsunmount_me_h)(mt_entry);
0251 
0252   if (mt_entry->unmount_task != 0) {
0253     rtems_status_code sc =
0254       rtems_event_transient_send(mt_entry->unmount_task);
0255     if (sc != RTEMS_SUCCESSFUL) {
0256       rtems_fatal_error_occurred(0xdeadbeef);
0257     }
0258   }
0259 
0260   free(mt_entry);
0261 }