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