1 = Filesystem Access = 2 3 Within the filesystem server library, a number of different abstractions and 4 mechanisms are employed to provide access to filesystem objects. 5 6 <<TableOfContents(2,3)>> 7 8 The abstractions or components used in the library are organised as follows. 9 10 ######## A graph showing the relationships between library components 11 12 {{{#!graphviz 13 #format svg 14 #transform notugly 15 digraph components { 16 node [fontsize="12.0",fontname="sans-serif",shape=box]; 17 edge [fontsize="12.0",fontname="sans-serif"]; 18 rankdir=LR; 19 20 subgraph { 21 rank=same; 22 23 Resource -> DirectoryResource -> FilePager 24 [dir=none,style=dotted]; 25 } 26 27 subgraph { 28 rank=same; 29 30 Provider -> DirectoryProvider -> FileProvider 31 [dir=none,style=dotted]; 32 } 33 34 subgraph { 35 rank=same; 36 37 Accessor -> Ext2FileAccessor 38 [dir=none,style=dotted]; 39 } 40 41 subgraph { 42 rank=same; 43 44 DirectoryAccessor -> Ext2DirectoryAccessor 45 [dir=none,style=dotted]; 46 } 47 48 subgraph { 49 node [shape=ellipse]; 50 rank=same; 51 52 Directory [label="dir"]; 53 File [label="dir/file"]; 54 } 55 56 DirectoryResource -> DirectoryProvider -> Ext2DirectoryAccessor -> Directory; 57 FilePager -> FileProvider -> Ext2FileAccessor -> File; 58 } 59 }}} 60 61 ######## 62 63 This document uses C-style interface syntax since the components operating 64 within the described mechanisms will themselves be described using such 65 syntax. 66 67 == Accountable == 68 69 This interface provides the following operations: 70 71 {{{ 72 void attach() 73 unsigned int detach() 74 }}} 75 76 Its purpose is to provide reference counting for components, with the `attach` 77 operation incrementing the number of users of a component, and with the 78 `detach` operation decrementing the number of users and returning the 79 resulting number of users. When components no longer have any attached users, 80 they may perform operations to tidy up after themselves and permit their 81 deallocation. 82 83 == Accessors == 84 85 Accessors provide the means of accessing filesystem object data and metadata. 86 Conceptually, files and directories are both exposed by accessors, although 87 the interfaces and mechanisms may differ between these types of objects. 88 89 === Directory Accessors === 90 91 Currently, directory accessors provide support for traversing directory 92 listings, obtaining the relevant filesystem metadata using the underlying 93 filesystem access library. 94 95 === File Accessors === 96 97 File content is accessed through an interface with the following operations: 98 99 {{{ 100 void close() 101 void fill(Flexpage *flexpage) 102 void flush(Flexpage *flexpage) 103 offset_t get_size() 104 void set_size(offset_t size) 105 }}} 106 107 The operations need to be supported with actual filesystem operations. For 108 example, ext2-based filesystems employ a specific abstraction which invokes 109 library functions provided by the `libext2fs` package. 110 111 == Providers == 112 113 Providers encapsulate the essential functionality for accessing filesystem 114 objects. Implementing the `Accountable` interface, they are shared by 115 resources and discarded when no resources are using them. 116 117 The following operations are supported by providers: 118 119 {{{ 120 ProviderRegistry *registry() 121 long make_resource(offset_t *size, object_flags_t *object_flags, Resource **resource) 122 bool removal_pending() 123 void remove() 124 void remove_pending(bool remove) 125 }}} 126 127 Providers are associated with filesystem objects in a registry which can be 128 obtained from each provider using the `registry` operation. 129 130 Providers also support the creation of resources through which each user of a 131 provider exercises its use of that provider. The `make_resource` operation 132 performs the creation and returns size, flags and resource instance details. 133 134 The removal of providers can be directed using the `remove_pending` and 135 `remove` operations. Where `remove_pending` has been called with a true value 136 as its parameter, the `removal_pending` operation will also return a true 137 value, and upon the provider being discarded, the `remove` operation will be 138 invoked. The `remove` operation performs the appropriate underlying operation 139 to remove the object being provided. 140 141 Typically, removal of providers is managed by the provider registry when 142 resources are closed and detached from providers. 143 144 ######## A graph showing the removal mechanism 145 146 {{{#!graphviz 147 #format svg 148 #transform notugly 149 digraph provider_removal { 150 node [fontsize="12.0",fontname="sans-serif",shape=box]; 151 edge [fontsize="12.0",fontname="sans-serif"]; 152 rankdir=LR; 153 154 ResourceServer -> Resource [label="close"]; 155 Resource -> ProviderRegistry [label="detach"]; 156 ProviderRegistry -> Provider [label="remove"]; 157 } 158 }}} 159 160 ######## 161 162 == Resources == 163 164 Resources are objects accessed by clients that support a basic level of 165 accounting and management. 166 167 The base interface of a resource is as follows: 168 169 {{{ 170 void activate() 171 void close() 172 }}} 173 174 Activation of a resource is an optional operation that performs any 175 initialisation before a resource is made available to its user. 176 177 In practice, other operations are required to make resources useful. 178 179 In some cases, resources provide the mechanism by which each user of a 180 filesystem object may access that object independently. They would then 181 effectively provide a session in which accesses can occur. 182 183 === Directory Resources === 184 185 Directory resources primarily expose the contents of directories in the 186 filesystem to a user. They employ directory accessors which concern themselves 187 with the actual filesystem content. 188 189 [[Components#Directories|Directory components]] are provided using directory 190 resources. 191 192 <<Anchor(Pager)>> 193 === Pagers or File Resources === 194 195 Pagers are resources that support dataspace access operations, thus allowing 196 the resources to expose filesystem content in mapped memory regions to a 197 particular user of the object providing the content. 198 199 [[Components#Files|File components]] and [[Components#Pipes|pipe components]] 200 are provided using pagers. 201 202 === Filesystem Resources === 203 204 Filesystem resources provide the entry point for access to a filesystem by 205 other components or programs. Since filesystems often enforce identity-based 206 access controls, a filesystem resource will typically support the 207 `open_for_user` operation in various forms, with the result of this operation 208 being the instantiation of an `OpenerResource` configured for the indicated 209 user identity. 210 211 == Registries == 212 213 The basic mechanism for obtaining a resource involves a registry, as 214 illustrated by the following diagram. 215 216 ######## A graph showing the use of a registry in obtaining resources 217 218 {{{#!graphviz 219 #format svg 220 #transform notugly 221 digraph registry { 222 node [fontsize="12.0",fontname="sans-serif",shape=box]; 223 edge [fontsize="12.0",fontname="sans-serif"]; 224 rankdir=LR; 225 226 subgraph { 227 node [label="OpenerContextResource"]; 228 rank=same; 229 230 OpenerContextResource1 -> OpenerContextResource2 [dir=none,style=dotted]; 231 } 232 233 subgraph { 234 node [label="OpenerResource"]; 235 rank=same; 236 237 OpenerResource1 -> OpenerResource2 [dir=none,style=dotted]; 238 } 239 240 subgraph { 241 rank=same; 242 243 ResourceRegistry -> Resource; 244 } 245 246 subgraph { 247 rank=same; 248 249 ProviderRegistry -> Provider; 250 } 251 252 OpenerContextResource1 -> OpenerResource1 [label="open"]; 253 OpenerResource1 -> ResourceRegistry [label="get_resource"]; 254 ResourceRegistry -> ProviderRegistry [label="get/set"]; 255 256 Provider -> Resource -> OpenerResource2 -> OpenerContextResource2; 257 } 258 }}} 259 260 ######## 261 262 The `ResourceRegistry` coordinates access to filesystem resources and, through 263 synchronisation, prevents conflicting operations from occurring concurrently. 264 For example, a removal operation on a file may not be allowed to occur while 265 an opening operation is in progress. 266 267 To achieve this, a common lock is employed to serialise access, with any 268 underlying filesystem operations being initiated from the registry while the 269 lock is held. An object providing the `FileOpening` interface for a filesystem 270 provides such operations, and the following interaction pattern is thereby 271 employed: 272 273 ######## A graph showing the registry coordinating filesystem operations 274 275 {{{#!graphviz 276 #format svg 277 #transform notugly 278 digraph registry_operations { 279 node [fontsize="12.0",fontname="sans-serif",shape=box]; 280 edge [fontsize="12.0",fontname="sans-serif"]; 281 rankdir=LR; 282 283 OpenerContextResource -> OpenerResource -> ResourceRegistry -> FileOpening; 284 } 285 }}} 286 287 ######## 288 289 Since the `ResourceRegistry` functionality is generic, it could be specialised 290 for each filesystem or be configured with an appropriate reference to a 291 `FileOpening` object. The `OpenerResource` would then be generic, invoking the 292 registry which would, in turn, invoke the opening object. 293 294 However, the chosen approach is to permit `OpenerResource` objects to 295 implement the `FileOpening` interface for each filesystem, meaning that the 296 `ResourceRegistry` will end up being called by the opener and then invoking 297 the opener in return. This is slightly more convenient than the alternative 298 since the opener can be configured with a given user identity, and such 299 identity details will ultimately be employed when accessing the underlying 300 filesystem itself.