1.1 --- a/docs/wiki/Client_Library Mon Nov 21 01:19:48 2022 +0100
1.2 +++ b/docs/wiki/Client_Library Thu Dec 01 17:55:12 2022 +0100
1.3 @@ -7,8 +7,8 @@
1.4 library, with the functions in the C library invoking client library functions
1.5 and employing client library structures internally.
1.6
1.7 -The client library is provided by `libfsclient` within the `departure`
1.8 -package.
1.9 +The client library is provided by [[Libraries#libfsclient|`libfsclient`]]
1.10 +within the `departure` package.
1.11
1.12 <<TableOfContents(2,3)>>
1.13
1.14 @@ -28,7 +28,7 @@
1.15
1.16 The members of the `file_t` data structure are as follows:
1.17
1.18 -|| '''Field''' || '''Description''' ||
1.19 +|| '''Member''' || '''Description''' ||
1.20 || `ref` || A reference to the component providing file content ||
1.21 || `memory` || The memory address of the exposed file region ||
1.22 || `start_pos` || The start position of the region in the file ||
1.23 @@ -203,18 +203,74 @@
1.24
1.25 === Notifications ===
1.26
1.27 -Since files and pipes may be accessed by multiple clients, necessarily for any
1.28 -sensible use of the latter, notifications can be configured to communicate a
1.29 -change in state to other users of these resources when they are accessed.
1.30 +Since files and pipes may be accessed by multiple clients, this being of
1.31 +particular significance for any real use of pipes, notifications can be
1.32 +configured to communicate a change in state to other users of these resources
1.33 +when they are accessed. Directories can also be monitored using notifications.
1.34
1.35 Notification types are specified using values encoding a number of flags, and
1.36 the following flags are available for this purpose:
1.37
1.38 || '''Flag''' || '''Notification Type''' ||
1.39 || `NOTIFY_CONTENT_AVAILABLE` || Content available to read ||
1.40 +|| `NOTIFY_FILE_OPENED` || File opened in directory ||
1.41 || `NOTIFY_PEER_CLOSED` || Other party has closed their endpoint ||
1.42 || `NOTIFY_SPACE_AVAILABLE` || Space available for writing ||
1.43
1.44 +The delivery of notifications is requested by subscribing to notifications for
1.45 +a given resource via a notifier object:
1.46 +
1.47 +{{{
1.48 +long client_subscribe(file_t *file, notify_flags_t flags, file_notifier_t *notifier);
1.49 +}}}
1.50 +
1.51 +A notifier object can be common throughout all threads in a task, being
1.52 +obtained using the following function:
1.53 +
1.54 +{{{
1.55 +file_notifier_t *client_notifier_task();
1.56 +}}}
1.57 +
1.58 +Alternatively, a local notifier can be created for use within a thread:
1.59 +
1.60 +{{{
1.61 +file_notifier_t *client_notifier_local();
1.62 +}}}
1.63 +
1.64 +Local notifiers must be closed when they are no longer needed:
1.65 +
1.66 +{{{
1.67 +void client_notifier_close(file_notifier_t *notifier);
1.68 +}}}
1.69 +
1.70 +When notifications are no longer needed, an unsubscribe operation can be
1.71 +invoked:
1.72 +
1.73 +{{{
1.74 +long client_unsubscribe(file_t *file, file_notifier_t *notifier);
1.75 +}}}
1.76 +
1.77 +==== Example ====
1.78 +
1.79 +{{{
1.80 +file_notifier_t *notifier = client_notifier_local();
1.81 +file_t *directory = client_open(filename, O_DIRECTORY);
1.82 +
1.83 +if (client_opened(directory))
1.84 +{
1.85 + if (!client_subscribe(directory, NOTIFY_FILE_OPENED, notifier))
1.86 + {
1.87 + if (!client_wait_file(directory, notifier))
1.88 + {
1.89 + /* File opened in directory. */
1.90 + }
1.91 + }
1.92 +}
1.93 +
1.94 +client_close(directory);
1.95 +client_notifier_close(notifier);
1.96 +}}}
1.97 +
1.98 === Blocking Operations ===
1.99
1.100 Reading and writing operations can be configured to block if data cannot be
1.101 @@ -228,3 +284,12 @@
1.102 For pipes, blocking behaviour is the default and must be disabled explicitly,
1.103 either by opening using the `O_NONBLOCK` flag or by calling
1.104 `client_set_blocking` with no flags set.
1.105 +
1.106 +Blocking behaviour is supported using the notification functionality. When
1.107 +access to a file or pipe cannot be satisfied for a particular operation, such
1.108 +as reading not being able to yield more content or writing not being able to
1.109 +submit more content, the task-level notifier will be used to wait for
1.110 +notifications applicable to the file or pipe involved. Consequently, the
1.111 +access will effectively block until notifications are delivered indicating
1.112 +that the state of the file or pipe has changed, and until it is determined
1.113 +that the change of state will allow the operation to proceed successfully.
2.1 --- a/docs/wiki/Components Mon Nov 21 01:19:48 2022 +0100
2.2 +++ b/docs/wiki/Components Thu Dec 01 17:55:12 2022 +0100
2.3 @@ -6,8 +6,9 @@
2.4 mechanisms for opening, reading, writing, and closing files, together with
2.5 various other operations.
2.6
2.7 -Components are provided by functionality in `libfsserver` used by programs
2.8 -found in the `servers` directory within the `departure` package.
2.9 +Components are provided by functionality in [[Libraries#libfsserver|
2.10 +`libfsserver`]] used by programs found in the `servers` directory within the
2.11 +`departure` package.
2.12
2.13 <<TableOfContents(2,3)>>
2.14
2.15 @@ -16,145 +17,6 @@
2.16 document are described using excerpts from the appropriate interface
2.17 descriptions.
2.18
2.19 -== Overview ==
2.20 -
2.21 -An overview of the component interactions involved in opening a file or
2.22 -directory is provided by the diagram below.
2.23 -
2.24 -######## A graph showing the interactions between components
2.25 -
2.26 -{{{#!graphviz
2.27 -#format svg
2.28 -#transform notugly
2.29 -digraph components {
2.30 - node [fontsize="12.0",fontname="sans-serif",shape=box];
2.31 - edge [fontsize="12.0",fontname="sans-serif"];
2.32 - rankdir=LR;
2.33 -
2.34 - subgraph {
2.35 - node [label="Client"];
2.36 - rank=min;
2.37 -
2.38 - Client1; Client2; Client3; Client4; Client5; Client6; Client7;
2.39 - }
2.40 -
2.41 - subgraph {
2.42 - rank=same;
2.43 -
2.44 - Memory [label="filename",shape=note];
2.45 - }
2.46 -
2.47 - subgraph {
2.48 - rank=max;
2.49 -
2.50 - Filesystem;
2.51 -
2.52 - subgraph {
2.53 - node [label="Opener\n(user)"];
2.54 - Opener1; Opener2;
2.55 - }
2.56 -
2.57 - subgraph {
2.58 - node [label="OpenerContext"];
2.59 - OpenerContext1; OpenerContext2; OpenerContext3;
2.60 - }
2.61 -
2.62 - Object [label="MappedFile\nor\nDirectory"];
2.63 - }
2.64 -
2.65 - Client1 -> Client2 -> Client3 -> Client4 -> Client5 -> Client6 -> Client7 [dir=none,style=dotted];
2.66 - Opener1 -> Opener2 [dir=none,style=dotted];
2.67 - OpenerContext1 -> OpenerContext2 -> OpenerContext3 [dir=none,style=dotted];
2.68 -
2.69 - Client1 -> Filesystem [label="open_for_user(user)"];
2.70 - Filesystem -> Opener1;
2.71 - Opener1 -> Client2;
2.72 -
2.73 - Client3 -> Opener2 [label="context()"];
2.74 - Opener2 -> OpenerContext1;
2.75 - OpenerContext1 -> Client4;
2.76 -
2.77 - Client5 -> Memory -> OpenerContext2;
2.78 -
2.79 - Client6 -> OpenerContext3 [label="open(flags, ...)"];
2.80 - OpenerContext3 -> Object;
2.81 - Object -> Client7;
2.82 -}
2.83 -}}}
2.84 -
2.85 -########
2.86 -
2.87 -In pseudocode, the operations as conducted by the client program are as
2.88 -follows:
2.89 -
2.90 -{{{
2.91 -opener = filesystem.open_for_user(user)
2.92 -context = opener.context()
2.93 -context.write("filename") # this being a memory access operation
2.94 -file = context.open(flags, ...)
2.95 -}}}
2.96 -
2.97 -Reading from an opened directory is achieved as shown in the following
2.98 -diagram.
2.99 -
2.100 -######## A graph showing the interactions between components
2.101 -
2.102 -{{{#!graphviz
2.103 -#format svg
2.104 -#transform notugly
2.105 -digraph components {
2.106 - node [fontsize="12.0",fontname="sans-serif",shape=box];
2.107 - edge [fontsize="12.0",fontname="sans-serif"];
2.108 - rankdir=LR;
2.109 -
2.110 - subgraph {
2.111 - node [label="Client"];
2.112 - rank=min;
2.113 -
2.114 - Client1; Client2; Client3; Client4;
2.115 - }
2.116 -
2.117 - subgraph {
2.118 - rank=same;
2.119 -
2.120 - Memory [label="entries",shape=note];
2.121 - }
2.122 -
2.123 - subgraph {
2.124 - rank=max;
2.125 -
2.126 - Directory;
2.127 -
2.128 - subgraph {
2.129 - node [label="Reader"];
2.130 -
2.131 - Reader1; Reader2; Reader3;
2.132 - }
2.133 - }
2.134 -
2.135 - Client1 -> Client2 -> Client3 -> Client4 [dir=none,style=dotted];
2.136 - Reader1 -> Reader2 -> Reader3 [dir=none,style=dotted];
2.137 -
2.138 - Client1 -> Directory [label="opendir()"];
2.139 - Directory -> Reader1;
2.140 - Reader1 -> Client2;
2.141 -
2.142 - Client3 -> Reader2 [label="current_region()"];
2.143 - Reader3 -> Memory -> Client4;
2.144 -}
2.145 -}}}
2.146 -
2.147 -########
2.148 -
2.149 -In pseudocode, the operations as conducted by the client program are as
2.150 -follows:
2.151 -
2.152 -{{{
2.153 -reader = directory.opendir()
2.154 -reader.current_region()
2.155 -entries = reader.read() # this being a memory access operation
2.156 -}}}
2.157 -
2.158 == Filesystems ==
2.159
2.160 Filesystems implement the `Filesystem` interface which provides the
2.161 @@ -167,6 +29,52 @@
2.162 The operation yields a file opener appropriate for the given [[Users|user]]
2.163 credentials.
2.164
2.165 +######## A graph showing the interactions between components
2.166 +
2.167 +{{{#!graphviz
2.168 +#format svg
2.169 +#transform notugly
2.170 +digraph open_for_user {
2.171 + node [fontsize="12.0",fontname="sans-serif",shape=box];
2.172 + edge [fontsize="12.0",fontname="sans-serif"];
2.173 + rankdir=LR;
2.174 +
2.175 + subgraph {
2.176 + node [label="Client"];
2.177 + rank=min;
2.178 +
2.179 + Client1; Client2;
2.180 + }
2.181 +
2.182 + subgraph {
2.183 + rank=max;
2.184 +
2.185 + Filesystem;
2.186 +
2.187 + subgraph {
2.188 + node [label="Opener\n(user)"];
2.189 + Opener;
2.190 + }
2.191 + }
2.192 +
2.193 + Client1 -> Client2 [dir=none,style=dotted];
2.194 +
2.195 + Client1 -> Filesystem [label="open_for_user(user)"];
2.196 + Filesystem -> Opener;
2.197 + Opener -> Client2;
2.198 +
2.199 +}
2.200 +}}}
2.201 +
2.202 +########
2.203 +
2.204 +In pseudocode, the operations as conducted by the client program are as
2.205 +follows:
2.206 +
2.207 +{{{
2.208 +opener = filesystem.open_for_user(user)
2.209 +}}}
2.210 +
2.211 ((Openers))
2.212 == File and Directory Openers ==
2.213
2.214 @@ -180,6 +88,54 @@
2.215 Each client program, task or thread obtains its own context because it will
2.216 need its own dedicated channel for communication with the filesystem.
2.217
2.218 +######## A graph showing the interactions between components
2.219 +
2.220 +{{{#!graphviz
2.221 +#format svg
2.222 +#transform notugly
2.223 +digraph context {
2.224 + node [fontsize="12.0",fontname="sans-serif",shape=box];
2.225 + edge [fontsize="12.0",fontname="sans-serif"];
2.226 + rankdir=LR;
2.227 +
2.228 + subgraph {
2.229 + node [label="Client"];
2.230 + rank=min;
2.231 +
2.232 + Client1; Client2;
2.233 + }
2.234 +
2.235 + subgraph {
2.236 + rank=max;
2.237 +
2.238 + subgraph {
2.239 + node [label="Opener\n(user)"];
2.240 + Opener;
2.241 + }
2.242 +
2.243 + subgraph {
2.244 + node [label="OpenerContext"];
2.245 + OpenerContext;
2.246 + }
2.247 + }
2.248 +
2.249 + Client1 -> Client2 [dir=none,style=dotted];
2.250 +
2.251 + Client1 -> Opener [label="context()"];
2.252 + Opener -> OpenerContext;
2.253 + OpenerContext -> Client2;
2.254 +}
2.255 +}}}
2.256 +
2.257 +########
2.258 +
2.259 +In pseudocode, the operations as conducted by the client program are as
2.260 +follows:
2.261 +
2.262 +{{{
2.263 +context = opener.context()
2.264 +}}}
2.265 +
2.266 == Opener Contexts ==
2.267
2.268 An opener context acts as a dataspace, meaning that it can be attached to a
2.269 @@ -205,6 +161,61 @@
2.270 Alongside regular files, directories may also be opened. Reading from them
2.271 yields a listing of directory entries.
2.272
2.273 +######## A graph showing the interactions between components
2.274 +
2.275 +{{{#!graphviz
2.276 +#format svg
2.277 +#transform notugly
2.278 +digraph open {
2.279 + node [fontsize="12.0",fontname="sans-serif",shape=box];
2.280 + edge [fontsize="12.0",fontname="sans-serif"];
2.281 + rankdir=LR;
2.282 +
2.283 + subgraph {
2.284 + node [label="Client"];
2.285 + rank=min;
2.286 +
2.287 + Client1; Client2; Client3;
2.288 + }
2.289 +
2.290 + subgraph {
2.291 + rank=same;
2.292 +
2.293 + Memory [label="filename",shape=note];
2.294 + }
2.295 +
2.296 + subgraph {
2.297 + rank=max;
2.298 +
2.299 + subgraph {
2.300 + node [label="OpenerContext"];
2.301 + OpenerContext1; OpenerContext2;
2.302 + }
2.303 +
2.304 + Object [label="MappedFile\nor\nDirectory"];
2.305 + }
2.306 +
2.307 + Client1 -> Client2 -> Client3 [dir=none,style=dotted];
2.308 + OpenerContext1 -> OpenerContext2 [dir=none,style=dotted];
2.309 +
2.310 + Client1 -> Memory -> OpenerContext1;
2.311 +
2.312 + Client2 -> OpenerContext2 [label="open(flags, ...)"];
2.313 + OpenerContext2 -> Object;
2.314 + Object -> Client3;
2.315 +}
2.316 +}}}
2.317 +
2.318 +########
2.319 +
2.320 +In pseudocode, the operations as conducted by the client program are as
2.321 +follows:
2.322 +
2.323 +{{{
2.324 +context.write("filename") # this being a memory access operation
2.325 +file = context.open(flags, ...)
2.326 +}}}
2.327 +
2.328 === Removing ===
2.329
2.330 Filesystem objects are removed by invoking the `remove` operation on an opener
2.331 @@ -292,6 +303,67 @@
2.332 supporting precisely the same navigation mechanisms as those supported by
2.333 files.
2.334
2.335 +Reading from an opened directory is achieved as shown in the following
2.336 +diagram.
2.337 +
2.338 +######## A graph showing the interactions between components
2.339 +
2.340 +{{{#!graphviz
2.341 +#format svg
2.342 +#transform notugly
2.343 +digraph components {
2.344 + node [fontsize="12.0",fontname="sans-serif",shape=box];
2.345 + edge [fontsize="12.0",fontname="sans-serif"];
2.346 + rankdir=LR;
2.347 +
2.348 + subgraph {
2.349 + node [label="Client"];
2.350 + rank=min;
2.351 +
2.352 + Client1; Client2; Client3; Client4;
2.353 + }
2.354 +
2.355 + subgraph {
2.356 + rank=same;
2.357 +
2.358 + Memory [label="entries",shape=note];
2.359 + }
2.360 +
2.361 + subgraph {
2.362 + rank=max;
2.363 +
2.364 + Directory;
2.365 +
2.366 + subgraph {
2.367 + node [label="Reader"];
2.368 +
2.369 + Reader1; Reader2; Reader3;
2.370 + }
2.371 + }
2.372 +
2.373 + Client1 -> Client2 -> Client3 -> Client4 [dir=none,style=dotted];
2.374 + Reader1 -> Reader2 -> Reader3 [dir=none,style=dotted];
2.375 +
2.376 + Client1 -> Directory [label="opendir()"];
2.377 + Directory -> Reader1;
2.378 + Reader1 -> Client2;
2.379 +
2.380 + Client3 -> Reader2 [label="current_region()"];
2.381 + Reader3 -> Memory -> Client4;
2.382 +}
2.383 +}}}
2.384 +
2.385 +########
2.386 +
2.387 +In pseudocode, the operations as conducted by the client program are as
2.388 +follows:
2.389 +
2.390 +{{{
2.391 +reader = directory.opendir()
2.392 +reader.current_region()
2.393 +entries = reader.read() # this being a memory access operation
2.394 +}}}
2.395 +
2.396 == Pipe Openers ==
2.397
2.398 Distinct from filesystems but potentially used by them, pipe openers provide a
3.1 --- a/docs/wiki/Filesystem_Access Mon Nov 21 01:19:48 2022 +0100
3.2 +++ b/docs/wiki/Filesystem_Access Thu Dec 01 17:55:12 2022 +0100
3.3 @@ -18,10 +18,17 @@
3.4 subgraph {
3.5 rank=same;
3.6
3.7 - Opener_note [shape=note,style=filled,fillcolor=gold,label="Exposes\nfile open\noperation"];
3.8 + Filesystem_note [shape=note,style=filled,fillcolor=gold,label="Configures opener\ncomponents"];
3.9 + Filesystem;
3.10 +
3.11 + Filesystem_note -> Filesystem [dir=none,style=dotted];
3.12 +
3.13 + open_for_user [fontsize="10.0",shape=ellipse];
3.14 +
3.15 Opener;
3.16 + Opener_note [shape=note,style=filled,fillcolor=gold,label="Exposes\nfile open\noperation"];
3.17
3.18 - Opener_note -> Opener [dir=none,style=dotted];
3.19 + Opener -> Opener_note [dir=none,style=dotted];
3.20 }
3.21
3.22 subgraph {
3.23 @@ -79,6 +86,11 @@
3.24 Accessor_note -> Accessor [dir=none,style=dotted];
3.25 }
3.26
3.27 + /* Configuring an opener. */
3.28 +
3.29 + Filesystem -> open_for_user [dir=none];
3.30 + open_for_user -> Opener;
3.31 +
3.32 /* Opening a file. */
3.33
3.34 Opener -> ResourceRegistry -> Resource;
3.35 @@ -99,6 +111,9 @@
3.36
3.37 ########
3.38
3.39 +Firstly, an `Opener` must be obtained from a `Filesystem`, this configuring
3.40 +the `Opener` for a particular user identity.
3.41 +
3.42 An `Opener` requests a `Resource` from a `ResourceRegistry`, each `Resource`
3.43 acting as a [[ServerLibrary#Pager|`Pager`]] and providing the actual access
3.44 mechanism to file content for a particular program. Since many programs may
3.45 @@ -518,6 +533,7 @@
3.46 ResourceServer -> Resource [label="close"];
3.47 Resource -> Provider [label="notify_others\nunsubscribe"];
3.48 Resource -> ProviderRegistry [label="detach"];
3.49 + ProviderRegistry -> Provider [label="detach\ndelete"];
3.50 }
3.51 }}}
3.52
4.1 --- a/docs/wiki/Server_Library Mon Nov 21 01:19:48 2022 +0100
4.2 +++ b/docs/wiki/Server_Library Thu Dec 01 17:55:12 2022 +0100
4.3 @@ -3,8 +3,8 @@
4.4 Within the filesystem server library, a number of different abstractions and
4.5 mechanisms are employed to provide access to filesystem objects.
4.6
4.7 -The server library is provided by `libfsserver` within the `departure`
4.8 -package.
4.9 +The server library is provided by [[Libraries#libfsserver|`libfsserver`]]
4.10 +within the `departure` package.
4.11
4.12 <<TableOfContents(2,3)>>
4.13
4.14 @@ -12,9 +12,10 @@
4.15 within the described mechanisms will themselves be described using such
4.16 syntax.
4.17
4.18 -== Accountable ==
4.19 +((Accountable))
4.20 +== Accountables ==
4.21
4.22 -This interface provides the following operations:
4.23 +The `Accountable` interface provides the following operations:
4.24
4.25 {{{
4.26 void attach();
4.27 @@ -28,6 +29,9 @@
4.28 they may perform operations to tidy up after themselves and permit their
4.29 deallocation.
4.30
4.31 +The [[#Provider|`Provider`]] abstraction employs this interface to record its
4.32 +usage by multiple resources.
4.33 +
4.34 == Accessors ==
4.35
4.36 Accessors provide the means of accessing filesystem object data and metadata.
4.37 @@ -40,9 +44,22 @@
4.38 listings, obtaining the relevant filesystem metadata using the underlying
4.39 filesystem access library.
4.40
4.41 +The `DirectoryAccessor` interface provides the following operation:
4.42 +
4.43 +{{{
4.44 +void read_directory(file_t *writer);
4.45 +}}}
4.46 +
4.47 +The `read_directory` operation is presented with a writer object into which
4.48 +directory listing data will be written. In the case of the ext2 directory
4.49 +accessor, the writer is presented to a directory iterator which traverses the
4.50 +directory data structure, invoking a callback sending directory entries via
4.51 +the writer to the client.
4.52 +
4.53 === File Accessors ===
4.54
4.55 -File content is accessed through an interface with the following operations:
4.56 +File content is accessed through the `Accessor` interface with the following
4.57 +operations:
4.58
4.59 {{{
4.60 void close();
4.61 @@ -54,15 +71,17 @@
4.62
4.63 The operations need to be supported with actual filesystem operations. For
4.64 example, ext2-based filesystems employ a specific abstraction which invokes
4.65 -library functions provided by the `libext2fs` package.
4.66 +library functions provided by [[Libraries#libext2fs|`libext2fs`]].
4.67
4.68 +((Provider))
4.69 == Providers ==
4.70
4.71 Providers encapsulate the essential functionality for accessing filesystem
4.72 objects. Implementing the `Accountable` interface, they are shared by
4.73 resources and discarded when no resources are using them.
4.74
4.75 -The following operations are supported by providers:
4.76 +The following operations are supported by providers as defined by the
4.77 +`Provider` interface:
4.78
4.79 {{{
4.80 ProviderRegistry *registry();
4.81 @@ -71,23 +90,34 @@
4.82 void remove_pending(bool remove);
4.83 }}}
4.84
4.85 -Providers are associated with filesystem objects in a registry which can be
4.86 -obtained from each provider using the `registry` operation.
4.87 +=== Origin and Ownership ===
4.88 +
4.89 +A provider is created to represent a filesystem object when an attempt is made
4.90 +to open that object. It is then recorded in a provider registry so that
4.91 +subsequent attempts to open the object yield a common provider instance. The
4.92 +provider registry having ownership of each provider can be obtained using its
4.93 +`registry` operation.
4.94 +
4.95 +See the [[Filesystem Access#Opening Files|file opening mechanism]] for details
4.96 +of the creation and registration of providers.
4.97 +
4.98 +=== Resource Creation ===
4.99
4.100 Providers also support the creation of resources through which each user of a
4.101 provider exercises its use of that provider. The `make_resource` operation
4.102 performs the creation and returns size, flags and resource instance details.
4.103
4.104 -The removal of providers can be directed using the `remove_pending` operation.
4.105 -Where `remove_pending` has been called with a true value as its parameter, the
4.106 -`removal_pending` operation will also return a true value, and upon the
4.107 -provider being discarded, a removal operation will be invoked on the
4.108 -underlying object being provided.
4.109 +See the [[Filesystem Access#Opening Files|file opening mechanism]] for details
4.110 +of resource creation.
4.111 +
4.112 +=== Deallocation ===
4.113
4.114 -Typically, removal of providers is managed by the provider registry when
4.115 -resources are closed and detached from providers.
4.116 +Deallocation of providers is managed by the provider registry when resources
4.117 +are closed and detached from providers. Since the registry effectively has
4.118 +ownership of the provider, having registered it, the registry must therefore
4.119 +be involved in its deallocation, deregistering it first.
4.120
4.121 -######## A graph showing the removal mechanism
4.122 +######## A graph showing the deallocation mechanism
4.123
4.124 {{{#!graphviz
4.125 #format svg
4.126 @@ -99,28 +129,56 @@
4.127
4.128 ResourceServer -> Resource [label="close"];
4.129 Resource -> ProviderRegistry [label="detach"];
4.130 - ProviderRegistry -> Provider [label="delete"];
4.131 + ProviderRegistry -> Provider [label="detach\ndelete"];
4.132 }
4.133 }}}
4.134
4.135 ########
4.136
4.137 +=== Filesystem Object Removal ===
4.138 +
4.139 +The removal of filesystem objects that are being represented by providers can
4.140 +be directed using the `remove_pending` operation. Where `remove_pending` has
4.141 +been called with a true value as its parameter, the `removal_pending`
4.142 +operation will also return a true value, and upon the provider being
4.143 +discarded, a removal operation will be invoked on the underlying object being
4.144 +provided.
4.145 +
4.146 +See the [[Filesystem Access#Removing Files|file removal mechanism]] for more
4.147 +details of the invocations involved.
4.148 +
4.149 +((Resource))
4.150 == Resources ==
4.151
4.152 Resources are objects accessed by clients that support a basic level of
4.153 -accounting and management.
4.154 +accounting and management. They act as servers and receive messages via the
4.155 +interprocess communication (IPC) mechanism.
4.156
4.157 -The base interface of a resource is as follows:
4.158 +The `Resource` abstraction is intended to work with lower-level mechanisms
4.159 +provided by [[Libraries#libipc|`libipc`]] involving data structures and
4.160 +functions that are usable in the C programming language. This abstraction
4.161 +integrates the fundamental `libipc` support with C++.
4.162 +
4.163 +The generic operations of the `Resource` interface are as follows:
4.164
4.165 {{{
4.166 void activate();
4.167 void close();
4.168 }}}
4.169
4.170 -Activation of a resource is an optional operation that performs any
4.171 -initialisation before a resource is made available to its user.
4.172 +The activation of a resource, supported by `activate`, is an optional
4.173 +operation that performs any initialisation before a resource is made available
4.174 +as a server.
4.175 +
4.176 +The `close` operation is invoked when resources are to be discarded.
4.177
4.178 -In practice, other operations are required to make resources useful.
4.179 +See the [[Filesystem Access#Closing Files|file closing mechanism]] for the
4.180 +context in which the `close` operation is invoked.
4.181 +
4.182 +In practice, other operations are required to make resources useful. Such
4.183 +other operations are provided by classes inheriting from `Resource` and thus
4.184 +specialising it. Such classes also inherit from IPC interface types so as to
4.185 +be able to support the invocation of operations exposed by such interfaces.
4.186
4.187 In some cases, resources provide the mechanism by which each user of a
4.188 filesystem object may access that object independently. They would then
4.189 @@ -154,6 +212,46 @@
4.190 being the instantiation of an `OpenerResource` configured for the indicated
4.191 user identity.
4.192
4.193 +=== Server Framework Integration ===
4.194 +
4.195 +Resources must also support specific operations for integration with the
4.196 +lower-level IPC handling implemented in `libipc`. The following operations
4.197 +will be invoked by the server framework in `libfsserver` to configure a server
4.198 +controlled by `libipc`:
4.199 +
4.200 +{{{
4.201 +int expected_items();
4.202 +ipc_server_handler_type handler();
4.203 +void *interface();
4.204 +}}}
4.205 +
4.206 +The `expected_items` operation returns the number of message items expected
4.207 +from clients invoking server operations exposed via IPC. Typically, the
4.208 +returned value will be calculated for a given server interface by a tool such
4.209 +as `idl`, provided by the idl4re distribution.
4.210 +
4.211 +The `handler` operation returns a reference to a handler function able to
4.212 +interpret the operation codes in incoming messages and to dispatch to the
4.213 +appropriate operations provided by the resource. Typically, such a function
4.214 +will be generated by a tool such as `idl`.
4.215 +
4.216 +The `interface` operation returns a pointer to the resource instance, coerced
4.217 +to an appropriate type for the handler function. Such a type will be that of
4.218 +the most specialised IPC interface type inherited by the resource
4.219 +implementation. The function returned by the `handler` operation will expect a
4.220 +pointer to an instance of this appropriate type.
4.221 +
4.222 +For example, consider the following:
4.223 +
4.224 +{{{
4.225 +class FilePager : public Pager, public MappedFileObject
4.226 +}}}
4.227 +
4.228 +Here, the `interface` operation will return a pointer coerced to
4.229 +`MappedFileObject`, and the `handler` operation will return a reference to a
4.230 +function expecting to be able to interpret this pointer as referring to
4.231 +precisely that type.
4.232 +
4.233 == Registries ==
4.234
4.235 The basic mechanism for obtaining a resource involves a registry, as
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/docs/wiki/Users Thu Dec 01 17:55:12 2022 +0100
5.3 @@ -0,0 +1,72 @@
5.4 += Users =
5.5 +
5.6 +Since filesystems such as ext2 employ the concepts of users and groups, and
5.7 +since access to such filesystems might be expected to respect the recorded
5.8 +user and group metadata, permitting or denying access to objects as
5.9 +appropriate, the need arises to define a user identity to control access to a
5.10 +filesystem server and the filesystem objects it exposes.
5.11 +
5.12 +== Opener Configuration ==
5.13 +
5.14 +Consequently, a filesystem server may not provide direct access to a
5.15 +filesystem. Instead, it may only expose the [[Components#Filesystems|
5.16 +`Filesystem`]] interface which provides the `open_for_user` operation. This
5.17 +operation is used to configure an [[Components#Openers|`Opener`]] that
5.18 +provides the actual interface for filesystem access as performed by a
5.19 +particular user.
5.20 +
5.21 +Since the `open_for_user` operation involves the indication of an arbitrary
5.22 +user identity, a server providing the `Filesystem` interface should only be
5.23 +exposed to appropriately privileged components. An `Opener` obtained from the
5.24 +operation can then be presented to a less privileged component.
5.25 +
5.26 +== User Structure ==
5.27 +
5.28 +Ordinarily, user information is exchanged using a `user_t` structure defined
5.29 +in [[Libraries#libsystypes|`libsystypes`]] with the following members:
5.30 +
5.31 +|| '''Member''' || '''Description''' ||
5.32 +|| `uid` || User identifier ||
5.33 +|| `gid` || Group identifier ||
5.34 +|| `umask` || File mode creation mask ||
5.35 +
5.36 +The information broadly follows that of a traditional Unix system. Other
5.37 +information, such as supplementary groups might conceivably be provided to the
5.38 +filesystem server separately. Indeed, the user structure might be simplified,
5.39 +removing the primary group information and providing this separately, too.
5.40 +
5.41 +== Opener Configuration in Ned ==
5.42 +
5.43 +The following example illustrates the configuration of an opener and the
5.44 +provision of the opener to a new task in the Lua-based scripting environment
5.45 +of the Ned component in L4Re:
5.46 +
5.47 +{{{
5.48 +-- Obtain user filesystems with umask 0022 (18).
5.49 +
5.50 +local open_for_user = 6;
5.51 +local ext2svr_paulb = L4.cast(L4.Proto.Factory, ext2svr):create(open_for_user, 1000, 1000, 18);
5.52 +
5.53 +l:startv({
5.54 + caps = {
5.55 + server = ext2svr_paulb,
5.56 + },
5.57 + log = { "client", "g" },
5.58 + },
5.59 + -- program, file to create
5.60 + "rom/dstest_file_client", "home/paulb/new file");
5.61 +}}}
5.62 +
5.63 +Here, `ext2svr_paulb` is an opener configured for the user `paulb` who has
5.64 +user and group identifiers of 1000. Since the Lua environment emphasises the
5.65 +L4Re factory mechanism, and since factory operations involve the use of L4Re
5.66 +variable-sized arguments ("vargs") as parameters, the signature of the factory
5.67 +version of the operation consists of the individual elements of the user
5.68 +abstraction:
5.69 +
5.70 +{{{
5.71 +open_for_user(in ipc_varg_sys_uid_t uid,
5.72 + in ipc_varg_sys_gid_t gid,
5.73 + in ipc_varg_sys_mode_t umask,
5.74 + out cap opener)
5.75 +}}}