1 = Mechanisms = 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 === Pagers or File Resources === 193 194 Pagers are resources that support dataspace access operations, thus allowing 195 the resources to expose filesystem content in mapped memory regions to a 196 particular user of the object providing the content. 197 198 [[Components#Files|File components]] and [[Components#Pipes|pipe components]] 199 are provided using pagers. 200 201 === Filesystem Resources === 202 203 Filesystem resources provide the entry point for access to a filesystem by 204 other components or programs. Since filesystems often enforce identity-based 205 access controls, a filesystem resource will typically support the 206 `open_for_user` operation in various forms, with the result of this operation 207 being the instantiation of an `OpenerResource` configured for the indicated 208 user identity. 209 210 == Registries == 211 212 The basic mechanism for obtaining a resource involves a registry, as 213 illustrated by the following diagram. 214 215 ######## A graph showing the use of a registry in obtaining resources 216 217 {{{#!graphviz 218 #format svg 219 #transform notugly 220 digraph registry { 221 node [fontsize="12.0",fontname="sans-serif",shape=box]; 222 edge [fontsize="12.0",fontname="sans-serif"]; 223 rankdir=LR; 224 225 subgraph { 226 node [label="OpenerContextResource"]; 227 rank=same; 228 229 OpenerContextResource1 -> OpenerContextResource2 [dir=none,style=dotted]; 230 } 231 232 subgraph { 233 node [label="OpenerResource"]; 234 rank=same; 235 236 OpenerResource1 -> OpenerResource2 [dir=none,style=dotted]; 237 } 238 239 subgraph { 240 rank=same; 241 242 ResourceRegistry -> Resource; 243 } 244 245 subgraph { 246 rank=same; 247 248 ProviderRegistry -> Provider; 249 } 250 251 OpenerContextResource1 -> OpenerResource1 [label="open"]; 252 OpenerResource1 -> ResourceRegistry [label="get_resource"]; 253 ResourceRegistry -> ProviderRegistry [label="get/set"]; 254 255 Provider -> Resource -> OpenerResource2 -> OpenerContextResource2; 256 } 257 }}} 258 259 ######## 260 261 The `ResourceRegistry` coordinates access to filesystem resources and, through 262 synchronisation, prevents conflicting operations from occurring concurrently. 263 For example, a removal operation on a file may not be allowed to occur while 264 an opening operation is in progress. 265 266 To achieve this, a common lock is employed to serialise access, with any 267 underlying filesystem operations being initiated from the registry while the 268 lock is held. An object providing the `FileOpening` interface for a filesystem 269 provides such operations, and the following interaction pattern is thereby 270 employed: 271 272 ######## A graph showing the registry coordinating filesystem operations 273 274 {{{#!graphviz 275 #format svg 276 #transform notugly 277 digraph registry_operations { 278 node [fontsize="12.0",fontname="sans-serif",shape=box]; 279 edge [fontsize="12.0",fontname="sans-serif"]; 280 rankdir=LR; 281 282 OpenerContextResource -> OpenerResource -> ResourceRegistry -> FileOpening; 283 } 284 }}} 285 286 ######## 287 288 Since the `ResourceRegistry` functionality is generic, it could be specialised 289 for each filesystem or be configured with an appropriate reference to a 290 `FileOpening` object. The `OpenerResource` would then be generic, invoking the 291 registry which would, in turn, invoke the opening object. 292 293 However, the chosen approach is to permit `OpenerResource` objects to 294 implement the `FileOpening` interface for each filesystem, meaning that the 295 `ResourceRegistry` will end up being called by the opener and then invoking 296 the opener in return. This is slightly more convenient than the alternative 297 since the opener can be configured with a given user identity, and such 298 identity details will ultimately be employed when accessing the underlying 299 filesystem itself.