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