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