1 = Filesystem Access = 2 3 Within the [[ServerLibrary|filesystem server library]], a number of different 4 abstractions and mechanisms are employed to provide access to filesystem 5 objects. An overview of these abstractions is presented below. 6 7 ######## A graph showing the relationships between filesystem access 8 ######## components 9 10 {{{#!graphviz 11 #format svg 12 #transform notugly 13 digraph components { 14 node [fontsize="12.0",fontname="sans-serif",shape=box]; 15 edge [fontsize="12.0",fontname="sans-serif"]; 16 rankdir=LR; 17 18 subgraph { 19 rank=same; 20 21 Filesystem_note [shape=note,style=filled,fillcolor=gold,label="Configures opener\ncomponents"]; 22 Filesystem; 23 24 Filesystem_note -> Filesystem [dir=none,style=dotted]; 25 26 open_for_user [fontsize="10.0",shape=ellipse]; 27 28 Opener; 29 Opener_note [shape=note,style=filled,fillcolor=gold,label="Exposes\nfile open\noperation"]; 30 31 Opener -> Opener_note [dir=none,style=dotted]; 32 } 33 34 subgraph { 35 rank=same; 36 37 ResourceRegistry_note [shape=note,style=filled,fillcolor=gold,label="Records\nopen file\nsessions"]; 38 ResourceRegistry; 39 40 ResourceRegistry_note -> ResourceRegistry [dir=none,style=dotted]; 41 } 42 43 subgraph { 44 rank=same; 45 46 Resource_note [shape=note,style=filled,fillcolor=gold,label="Provides\nfilesystem\ncontent"]; 47 Resource [label="Resource\n(Pager)"]; 48 49 Resource_note -> Resource [dir=none,style=dotted]; 50 } 51 52 subgraph { 53 rank=same; 54 55 Provider_note [shape=note,style=filled,fillcolor=gold,label="Represents\nopen file"]; 56 Provider; 57 58 Provider_note -> Provider [dir=none,style=dotted]; 59 } 60 61 subgraph { 62 rank=same; 63 64 PageMapper_note [shape=note,style=filled,fillcolor=gold,label="Provides\npopulated\nfile pages"]; 65 PageMapper; 66 67 PageMapper_note -> PageMapper [dir=none,style=dotted]; 68 } 69 70 ProviderRegistry [shape=record,label="<head> ProviderRegistry | ... | { file-n | provider-n } | ... "]; 71 72 subgraph { 73 rank=same; 74 75 FileOpening_note [shape=note,style=filled,fillcolor=gold,label="Exposes\nfilesystem\nfunctionality"]; 76 FileOpening; 77 78 FileOpening_note -> FileOpening [dir=none,style=dotted]; 79 } 80 81 subgraph { 82 rank=same; 83 84 Accessor_note [shape=note,style=filled,fillcolor=gold,label="Populates\nfile pages"]; 85 Accessor; 86 Accessor_note -> Accessor [dir=none,style=dotted]; 87 } 88 89 /* Configuring an opener. */ 90 91 Filesystem -> open_for_user [dir=none]; 92 open_for_user -> Opener; 93 94 /* Opening a file. */ 95 96 Opener -> ResourceRegistry -> Resource; 97 ResourceRegistry -> FileOpening; 98 99 Provider -> PageMapper; 100 FileOpening -> Accessor; 101 102 /* Closing a file. */ 103 104 Resource -> Provider -> ProviderRegistry:head; 105 106 /* Open file management. */ 107 108 ResourceRegistry -> ProviderRegistry:head; 109 } 110 }}} 111 112 ######## 113 114 Firstly, an `Opener` must be obtained from a `Filesystem`, this configuring 115 the `Opener` for a particular user identity. 116 117 An `Opener` requests a `Resource` from a `ResourceRegistry`, each `Resource` 118 acting as a [[ServerLibrary#Pager|`Pager`]] and providing the actual access 119 mechanism to file content for a particular program. Since many programs may 120 access the same file simultaneously, a `Provider` object represents a file 121 opened in the system, retaining a `PageMapper` that coordinates the collective 122 access to the file (see the [[Paging|paging documentation]] for more 123 information). 124 125 A `ProviderRegistry` maintains the record of opened files, yielding a new 126 `Provider` for an unopened file or an existing `Provider` for a file that is 127 already open. The `ProviderRegistry` monitors the usage of files, discarding 128 any `Provider` no longer in use. 129 130 == Opening Files == 131 132 Opening a file involves the identification of the filesystem object involved, 133 the acquisition of a `Provider` representing the file, and the creation of a 134 `Resource` to deliver file content to the requesting program. 135 136 ######## A graph showing the opening mechanism for an already-open file 137 138 {{{#!graphviz 139 #format svg 140 #transform notugly 141 digraph opening_open { 142 node [fontsize="12.0",fontname="sans-serif",shape=box]; 143 edge [fontsize="12.0",fontname="sans-serif"]; 144 rankdir=LR; 145 146 subgraph { 147 rank=same; 148 149 Opener_note [shape=note,style=filled,fillcolor=gold,label="Exposes\nfile open\noperation"]; 150 Opener; 151 152 Opener_note -> Opener [dir=none,style=dotted]; 153 } 154 155 subgraph { 156 rank=same; 157 158 ResourceRegistry_note [shape=note,style=filled,fillcolor=gold,label="Records\nopen file\nsessions"]; 159 ResourceRegistry; 160 161 Resource_returned [label="Resource\n(Pager)"]; 162 Resource_returned_note [shape=note,style=filled,fillcolor=gold,label="Provides\nfilesystem\ncontent"]; 163 164 ResourceRegistry_note -> ResourceRegistry [dir=none,style=dotted]; 165 Resource_returned -> Resource_returned_note [dir=none,style=dotted]; 166 } 167 168 subgraph { 169 rank=same; 170 171 Resource [label="Resource\n(Pager)"]; 172 173 FileOpening_note [shape=note,style=filled,fillcolor=gold,label="Exposes\nfilesystem\nfunctionality"]; 174 FileOpening; 175 176 FileOpening_note -> FileOpening [dir=none,style=dotted]; 177 } 178 179 subgraph { 180 rank=max; 181 182 ProviderRegistry_note [shape=note,style=filled,fillcolor=gold,label="Provides\nopen files"]; 183 ProviderRegistry; 184 185 Provider; 186 Provider_note [shape=note,style=filled,fillcolor=gold,label="Represents\nopen file"]; 187 188 ProviderRegistry_note -> ProviderRegistry [dir=none,style=dotted]; 189 Provider -> Provider_note [dir=none,style=dotted]; 190 } 191 192 /* Obtaining a resource from the registry. */ 193 194 Opener -> ResourceRegistry [label="get_resource"]; 195 ResourceRegistry -> Resource_returned [dir=none]; 196 Resource_returned -> Opener; 197 198 /* Obtaining a provider. */ 199 200 ResourceRegistry -> FileOpening [label="get_fileid"]; 201 ResourceRegistry -> ProviderRegistry [label="get(fileid)"]; 202 ProviderRegistry -> Provider; 203 204 /* Obtaining the resource from the provider. */ 205 206 ResourceRegistry -> Provider [label="make_resource"]; 207 Provider -> Resource [dir=none]; 208 Resource -> ResourceRegistry; 209 } 210 }}} 211 212 ######## 213 214 Where a provider does not already exist, with the file not having been opened 215 already, some extra interactions occur: 216 217 ######## A graph showing opening mechanism details for an unopened file 218 219 {{{#!graphviz 220 #format svg 221 #transform notugly 222 digraph opening_unopened { 223 node [fontsize="12.0",fontname="sans-serif",shape=box]; 224 edge [fontsize="12.0",fontname="sans-serif"]; 225 rankdir=LR; 226 227 Opener; 228 229 ResourceRegistry; 230 231 subgraph { 232 rank=same; 233 234 Provider_note [shape=note,style=filled,fillcolor=gold,label="Created\nand set in\nregistry"]; 235 Provider; 236 237 Accessor; 238 PageMapper; 239 PageMapper_note [shape=note,style=filled,fillcolor=gold,label="Created\nfor provider"]; 240 241 Provider_note -> Provider [dir=none,style=dotted]; 242 PageMapper -> PageMapper_note [dir=none,style=dotted]; 243 } 244 245 subgraph { 246 rank=max; 247 248 ProviderRegistry_note [shape=note,style=filled,fillcolor=gold,label="Records\nopen files"]; 249 ProviderRegistry; 250 FileOpening; 251 FileOpening_note [shape=note,style=filled,fillcolor=gold,label="Exposes\nfilesystem\nfunctionality"]; 252 253 ProviderRegistry_note -> ProviderRegistry [dir=none,style=dotted]; 254 FileOpening -> FileOpening_note [dir=none,style=dotted]; 255 } 256 257 Opener -> ResourceRegistry [dir=none,style=dashed]; 258 259 /* Obtaining a new provider. */ 260 261 ResourceRegistry -> FileOpening [label="make_accessor"]; 262 FileOpening -> Accessor [dir=none]; 263 Accessor -> PageMapper -> ResourceRegistry; 264 265 ResourceRegistry -> Provider [dir=none]; 266 Provider -> ProviderRegistry [label="set(fileid)"]; 267 } 268 }}} 269 270 ######## 271 272 The `Resource` obtained to deliver file content to a client will be served by 273 a distinct thread through a dedicated communications endpoint, leaving the 274 `Opener` available to satisfy other requests. This new thread will remain 275 active while a file remains open, being terminated when the file is closed and 276 the communications endpoint released by the client. 277 278 == Notifications == 279 280 Within the filesystem access architecture, users of files may act in ways that 281 may notify other users of the same file. To support such notifications, an 282 interface is provided for filesystem clients to subscribe and unsubscribe to 283 notifications. The notifications themselves occur when files are opened, 284 modified and closed. Pipes also generate notifications when a pipe reader 285 makes more space available for the writer. 286 287 ######## A graph showing subscription to notifications 288 289 {{{#!graphviz 290 #format svg 291 #transform notugly 292 digraph notification_subscriptions { 293 node [fontsize="12.0",fontname="sans-serif",shape=box]; 294 edge [fontsize="12.0",fontname="sans-serif"]; 295 rankdir=LR; 296 297 subgraph { 298 rank=same; 299 300 Client1 [label="Client\nprogram"]; 301 Client2 [label="Client\nprogram"]; 302 } 303 304 subgraph { 305 rank=same; 306 307 Notifier1_note [shape=note,style=filled,fillcolor=gold,label="Created for\nnotifications"]; 308 Notifier1 [label="Notifier"]; 309 Notifier2 [label="Notifier"]; 310 311 Notifier1_note -> Notifier1 -> Notifier2 [dir=none,style=dotted]; 312 } 313 314 subgraph { 315 rank=same; 316 317 Resource1 [label="Resource\n(Pager)"]; 318 Resource2 [label="Resource\n(Pager)"]; 319 } 320 321 subgraph { 322 rank=same; 323 324 Notifier1_subscribe_note [shape=note,style=filled,fillcolor=gold,label="Propagated to\nprovider"]; 325 Notifier1_subscribe [label="Notifier"]; 326 Notifier2_subscribe [label="Notifier"]; 327 328 Notifier1_subscribe_note -> Notifier1_subscribe -> Notifier2_subscribe [dir=none,style=dotted]; 329 } 330 331 subgraph { 332 rank=same; 333 334 Provider_note [shape=note,style=filled,fillcolor=gold,label="Manages file\nsubscriptions"]; 335 Provider [label="Provider"]; 336 337 Provider_note -> Provider [dir=none,style=dotted]; 338 } 339 340 /* Subscribing. */ 341 342 Client1 -> Notifier1 [dir=none]; 343 Notifier1 -> Resource1 [label="subscribe"]; 344 345 Resource1 -> Notifier1_subscribe [dir=none]; 346 Notifier1_subscribe -> Provider [label="subscribe"]; 347 348 Client2 -> Notifier2 [dir=none]; 349 Notifier2 -> Resource2 [label="subscribe"]; 350 351 Resource2 -> Notifier2_subscribe [dir=none]; 352 Notifier2_subscribe -> Provider [label="subscribe"]; 353 } 354 }}} 355 356 ######## 357 358 An example of a notification scenario is given below: 359 360 ######## A graph showing notification 361 362 {{{#!graphviz 363 #format svg 364 #transform notugly 365 digraph notifications { 366 node [fontsize="12.0",fontname="sans-serif",shape=box]; 367 edge [fontsize="12.0",fontname="sans-serif"]; 368 rankdir=LR; 369 370 subgraph { 371 rank=same; 372 373 Client1 [label="Client\nprogram"]; 374 Client2 [label="Client\nprogram"]; 375 } 376 377 subgraph { 378 rank=same; 379 380 Notifier1_note [shape=note,style=filled,fillcolor=gold,label="Registered for\nnotifications"]; 381 Notifier1 [label="Notifier"]; 382 383 Resource2 [label="Resource\n(Pager)"]; 384 Resource2_note [shape=note,style=filled,fillcolor=gold,label="Generates\nnotification"]; 385 386 Notifier1_note -> Notifier1 [dir=none,style=dotted]; 387 Resource2 -> Resource2_note [dir=none,style=dotted]; 388 } 389 390 subgraph { 391 rank=same; 392 393 Provider_note [shape=note,style=filled,fillcolor=gold,label="Propagates\nnotifications"]; 394 Provider [label="Provider"]; 395 396 Provider_note -> Provider [dir=none,style=dotted]; 397 } 398 399 /* A notification scenario. */ 400 401 Client2 -> Resource2 [label="resize"]; 402 Resource2 -> Provider [label="notify_others"]; 403 Provider -> Notifier1 [label="notify"]; 404 Client1 -> Notifier1 [label="wait"]; 405 } 406 }}} 407 408 ######## 409 410 Notifications provide the basis for blocking reading and writing operations, 411 with pipe endpoints depending on such blocking for efficient use of pipes. The 412 interactions involved when transferring data through pipes are depicted below. 413 414 ######## A graph showing notifications employed by pipe endpoints 415 416 {{{#!graphviz 417 #format svg 418 #transform notugly 419 digraph pipe_notifications { 420 node [fontsize="12.0",fontname="sans-serif",shape=box]; 421 edge [fontsize="12.0",fontname="sans-serif"]; 422 rankdir=LR; 423 424 subgraph { 425 rank=min; 426 427 Client1_note [shape=note,style=filled,fillcolor=gold,label="Fill pipe\nthen request\nmore space"]; 428 Client1 [label="Client\nprogram\n(writer)"]; 429 Client1_wait_note [shape=note,style=filled,fillcolor=gold,label="Waiting after\nfilling pipe"]; 430 Client1_wait [label="Client\nprogram\n(writer)"]; 431 432 Client1_note -> Client1 [dir=none,style=dotted]; 433 Client1_wait_note -> Client1_wait [dir=none,style=dotted]; 434 435 Client1 -> Client1_wait_note [dir=none,style=invis]; 436 } 437 438 subgraph { 439 rank=max; 440 441 Client2_note [shape=note,style=filled,fillcolor=gold,label="Waiting for\nmore content\nbefore reading"]; 442 Client2 [label="Client\nprogram\n(reader)"]; 443 Client2_read_note [shape=note,style=filled,fillcolor=gold,label="Empty pipe\nthen request\nmore content"]; 444 Client2_read [label="Client\nprogram\n(reader)"]; 445 446 Client2_note -> Client2 [dir=none,style=dotted]; 447 Client2_read_note -> Client2_read [dir=none,style=dotted]; 448 } 449 450 subgraph { 451 rank=same; 452 453 Notifier1 [label="Notifier"]; 454 Resource1 [label="Resource\n(PipePager)"]; 455 } 456 457 subgraph { 458 rank=same; 459 460 Notifier2 [label="Notifier"]; 461 Resource2 [label="Resource\n(PipePager)"]; 462 } 463 464 subgraph { 465 rank=same; 466 467 PipePaging [label="Provider\n(PipePaging)"]; 468 PipePaging_space [label="Provider\n(PipePaging)"]; 469 } 470 471 /* Making content available. */ 472 473 Client1 -> Resource1 [label="next_region"]; 474 Resource1 -> PipePaging [label="add_region"]; 475 PipePaging -> Notifier2 [label="notify"]; 476 Client2 -> Notifier2 [label="wait"]; 477 478 /* Making space available. */ 479 480 Client2_read -> Resource2 [label="next_region"]; 481 Resource2 -> PipePaging_space [label="next_region"]; 482 PipePaging_space -> Notifier1 [label="notify"]; 483 Client1_wait -> Notifier1 [label="wait"]; 484 } 485 }}} 486 487 ######## 488 489 == Closing Files == 490 491 Files are closed when client programs release their references to the resource 492 capabilities used to access files. The mechanism by which this is done 493 involves the registration of an IRQ object that is bound to the same thread as 494 the one used by resources to service file access requests. This IRQ object is 495 associated with the IPC gate through which such requests occur, and the IRQ 496 object is configured to deliver an interrupt message when the final reference 497 to the IPC gate has been released. 498 499 When a client program terminates, its references to capabilities should be 500 released, and this should cause a reference counter associated with the IPC 501 gate to decrement. Upon the loss of the final reference and the delivery of 502 the interrupt, the server framework will call a `close` method on the 503 `Resource` object concerned, this implementing the 504 [[ServerLibrary#Accountable|`Accountable`]] interface. 505 506 ######## A graph showing the closing mechanism 507 508 {{{#!graphviz 509 #format svg 510 #transform notugly 511 digraph closing { 512 node [fontsize="12.0",fontname="sans-serif",shape=box]; 513 edge [fontsize="12.0",fontname="sans-serif"]; 514 rankdir=LR; 515 516 Client [label="Client\nprogram"]; 517 518 subgraph { 519 rank=same; 520 521 Gate_note [shape=note,style=filled,fillcolor=gold,label="Actual\nendpoint"]; 522 Gate [label="IPC gate",shape="octagon"]; 523 IRQ [shape="triangle"]; 524 ResourceServer; 525 ResourceServer_note [shape=note,style=filled,fillcolor=gold,label="Handles\nrequests"]; 526 527 Gate_note -> Gate [dir=none,style=dotted]; 528 ResourceServer -> ResourceServer_note [dir=none,style=dotted]; 529 } 530 531 Resource [label="Resource\n(Pager)"]; 532 533 Provider; 534 535 ProviderRegistry; 536 537 Client -> Gate [style=dashed,label="(release)"]; 538 Gate -> IRQ -> ResourceServer; 539 ResourceServer -> Resource [label="close"]; 540 Resource -> Provider [label="notify_others\nunsubscribe"]; 541 Resource -> ProviderRegistry [label="detach"]; 542 ProviderRegistry -> Provider [label="detach\ndelete"]; 543 } 544 }}} 545 546 ######## 547 548 As a consequence of closing a file, an `unsubscribe` operation performed on 549 the `Provider` should cause any `Notifier` objects associated with the 550 `Resource` object to be released. Meanwhile, the `ResourceServer` will discard 551 the `Resource` object before the server thread terminates. 552 553 == Removing Files == 554 555 Unix filesystem semantics typically allow a file to be "unlinked" while still 556 being accessed by a program, with accesses still being directed to the file, 557 but with the file being removed from a directory and potentially being 558 replaced by another file. To support this, a mechanism is provided to defer 559 any removal of an open file. 560 561 ######## A graph showing the removal mechanism 562 563 {{{#!graphviz 564 #format svg 565 #transform notugly 566 digraph removing { 567 node [fontsize="12.0",fontname="sans-serif",shape=box]; 568 edge [fontsize="12.0",fontname="sans-serif"]; 569 rankdir=LR; 570 571 subgraph { 572 rank=same; 573 574 Client1_note [shape=note,style=filled,fillcolor=gold,label="Removing\nopen file"]; 575 Client1 [label="Client\nprogram"]; 576 Client2 [label="Client\nprogram"]; 577 Client2_note [shape=note,style=filled,fillcolor=gold,label="Closes\nopen file"]; 578 579 Client1_note -> Client1 [dir=none,style=dotted]; 580 Client2 -> Client2_note [dir=none,style=dotted]; 581 582 Client1 -> Client2 [dir=none,style=invis]; 583 } 584 585 subgraph { 586 rank=same; 587 588 Resource [label="Resource\n(Pager)"]; 589 Opener; 590 } 591 592 subgraph { 593 rank=same; 594 595 Provider1 [label="Provider"]; 596 Provider1_note [shape=note,style=filled,fillcolor=gold,label="Maintains\nremoval\nstate"]; 597 Provider2 [label="Provider"]; 598 599 Provider1 -> Provider1_note -> Provider2 [dir=none,style=dotted]; 600 } 601 602 ProviderRegistry1 [label="ProviderRegistry"]; 603 ProviderRegistry2 [label="ProviderRegistry"]; 604 605 subgraph { 606 rank=same; 607 608 FileOpening; 609 Accessor_note [shape=note,style=filled,fillcolor=gold,label="Performing\nfilesystem\noperations"]; 610 Accessor; 611 612 FileOpening -> Accessor_note -> Accessor [dir=none,style=dotted]; 613 } 614 615 /* Removing the file while it remains open. */ 616 617 Client1 -> Opener [label="remove\n(via context)"]; 618 Opener -> ResourceRegistry [label="remove_provider"]; 619 ResourceRegistry -> FileOpening [label="get_fileid\nunlink_object"]; 620 ResourceRegistry -> ProviderRegistry1 [label="get(fileid)"]; 621 ResourceRegistry -> Provider1 [label="remove_pending"]; 622 623 /* File closure and deferred removal. */ 624 625 Client2 -> Resource [label="close"]; 626 Resource -> Provider2 [label="notify_others\nunsubscribe"]; 627 Resource -> ProviderRegistry2 [label="detach"]; 628 ProviderRegistry2 -> Provider2 [label="remove"]; 629 Provider2 -> Accessor [label="remove"]; 630 } 631 }}} 632 633 ########