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 == Notifications == 273 274 Within the filesystem access architecture, users of files may act in ways that 275 may notify other users of the same file. To support such notifications, an 276 interface is provided for filesystem clients to subscribe and unsubscribe to 277 notifications. The notifications themselves occur when files are opened, 278 modified and closed. Pipes also generate notifications when a pipe reader 279 makes more space available for the writer. 280 281 ######## A graph showing subscription to notifications 282 283 {{{#!graphviz 284 #format svg 285 #transform notugly 286 digraph notification_subscriptions { 287 node [fontsize="12.0",fontname="sans-serif",shape=box]; 288 edge [fontsize="12.0",fontname="sans-serif"]; 289 rankdir=LR; 290 291 subgraph { 292 rank=same; 293 294 Client1 [label="Client\nprogram"]; 295 Client2 [label="Client\nprogram"]; 296 } 297 298 subgraph { 299 rank=same; 300 301 Notifier1_note [shape=note,style=filled,fillcolor=gold,label="Created for\nnotifications"]; 302 Notifier1 [label="Notifier"]; 303 Notifier2 [label="Notifier"]; 304 305 Notifier1_note -> Notifier1 -> Notifier2 [dir=none,style=dotted]; 306 } 307 308 subgraph { 309 rank=same; 310 311 Resource1 [label="Resource\n(Pager)"]; 312 Resource2 [label="Resource\n(Pager)"]; 313 } 314 315 subgraph { 316 rank=same; 317 318 Notifier1_subscribe_note [shape=note,style=filled,fillcolor=gold,label="Propagated to\nprovider"]; 319 Notifier1_subscribe [label="Notifier"]; 320 Notifier2_subscribe [label="Notifier"]; 321 322 Notifier1_subscribe_note -> Notifier1_subscribe -> Notifier2_subscribe [dir=none,style=dotted]; 323 } 324 325 subgraph { 326 rank=same; 327 328 Provider_note [shape=note,style=filled,fillcolor=gold,label="Manages file\nsubscriptions"]; 329 Provider [label="Provider"]; 330 331 Provider_note -> Provider [dir=none,style=dotted]; 332 } 333 334 /* Subscribing. */ 335 336 Client1 -> Notifier1 [dir=none]; 337 Notifier1 -> Resource1 [label="subscribe"]; 338 339 Resource1 -> Notifier1_subscribe [dir=none]; 340 Notifier1_subscribe -> Provider [label="subscribe"]; 341 342 Client2 -> Notifier2 [dir=none]; 343 Notifier2 -> Resource2 [label="subscribe"]; 344 345 Resource2 -> Notifier2_subscribe [dir=none]; 346 Notifier2_subscribe -> Provider [label="subscribe"]; 347 } 348 }}} 349 350 ######## 351 352 An example of a notification scenario is given below: 353 354 ######## A graph showing notification 355 356 {{{#!graphviz 357 #format svg 358 #transform notugly 359 digraph notifications { 360 node [fontsize="12.0",fontname="sans-serif",shape=box]; 361 edge [fontsize="12.0",fontname="sans-serif"]; 362 rankdir=LR; 363 364 subgraph { 365 rank=same; 366 367 Client1 [label="Client\nprogram"]; 368 Client2 [label="Client\nprogram"]; 369 } 370 371 subgraph { 372 rank=same; 373 374 Notifier1_note [shape=note,style=filled,fillcolor=gold,label="Registered for\nnotifications"]; 375 Notifier1 [label="Notifier"]; 376 377 Resource2 [label="Resource\n(Pager)"]; 378 Resource2_note [shape=note,style=filled,fillcolor=gold,label="Generates\nnotification"]; 379 380 Notifier1_note -> Notifier1 [dir=none,style=dotted]; 381 Resource2 -> Resource2_note [dir=none,style=dotted]; 382 } 383 384 subgraph { 385 rank=same; 386 387 Provider_note [shape=note,style=filled,fillcolor=gold,label="Propagates\nnotifications"]; 388 Provider [label="Provider"]; 389 390 Provider_note -> Provider [dir=none,style=dotted]; 391 } 392 393 /* A notification scenario. */ 394 395 Client2 -> Resource2 [label="resize"]; 396 Resource2 -> Provider [label="notify_others"]; 397 Provider -> Notifier1 [label="notify"]; 398 Client1 -> Notifier1 [label="wait"]; 399 } 400 }}} 401 402 ######## 403 404 Notifications provide the basis for blocking reading and writing operations, 405 with pipe endpoints depending on such blocking for efficient use of pipes. The 406 interactions involved when transferring data through pipes are depicted below. 407 408 ######## A graph showing notifications employed by pipe endpoints 409 410 {{{#!graphviz 411 #format svg 412 #transform notugly 413 digraph pipe_notifications { 414 node [fontsize="12.0",fontname="sans-serif",shape=box]; 415 edge [fontsize="12.0",fontname="sans-serif"]; 416 rankdir=LR; 417 418 subgraph { 419 rank=min; 420 421 Client1_note [shape=note,style=filled,fillcolor=gold,label="Fill pipe\nthen request\nmore space"]; 422 Client1 [label="Client\nprogram\n(writer)"]; 423 Client1_wait_note [shape=note,style=filled,fillcolor=gold,label="Waiting after\nfilling pipe"]; 424 Client1_wait [label="Client\nprogram\n(writer)"]; 425 426 Client1_note -> Client1 [dir=none,style=dotted]; 427 Client1_wait_note -> Client1_wait [dir=none,style=dotted]; 428 429 Client1 -> Client1_wait_note [dir=none,style=invis]; 430 } 431 432 subgraph { 433 rank=max; 434 435 Client2_note [shape=note,style=filled,fillcolor=gold,label="Waiting for\nmore content\nbefore reading"]; 436 Client2 [label="Client\nprogram\n(reader)"]; 437 Client2_read_note [shape=note,style=filled,fillcolor=gold,label="Empty pipe\nthen request\nmore content"]; 438 Client2_read [label="Client\nprogram\n(reader)"]; 439 440 Client2_note -> Client2 [dir=none,style=dotted]; 441 Client2_read_note -> Client2_read [dir=none,style=dotted]; 442 } 443 444 subgraph { 445 rank=same; 446 447 Notifier1 [label="Notifier"]; 448 Resource1 [label="Resource\n(PipePager)"]; 449 } 450 451 subgraph { 452 rank=same; 453 454 Notifier2 [label="Notifier"]; 455 Resource2 [label="Resource\n(PipePager)"]; 456 } 457 458 subgraph { 459 rank=same; 460 461 PipePaging [label="Provider\n(PipePaging)"]; 462 PipePaging_space [label="Provider\n(PipePaging)"]; 463 } 464 465 /* Making content available. */ 466 467 Client1 -> Resource1 [label="next_region"]; 468 Resource1 -> PipePaging [label="add_region"]; 469 PipePaging -> Notifier2 [label="notify"]; 470 Client2 -> Notifier2 [label="wait"]; 471 472 /* Making space available. */ 473 474 Client2_read -> Resource2 [label="next_region"]; 475 Resource2 -> PipePaging_space [label="next_region"]; 476 PipePaging_space -> Notifier1 [label="notify"]; 477 Client1_wait -> Notifier1 [label="wait"]; 478 } 479 }}} 480 481 ######## 482 483 == Closing Files == 484 485 Files are closed when client programs release their references to the resource 486 capabilities used to access files. The mechanism by which this is done 487 involves the registration of an IRQ object that is bound to the same thread as 488 the one used by resources to service file access requests. This IRQ object is 489 associated with the IPC gate through which such requests occur, and the IRQ 490 object is configured to deliver an interrupt message when the final reference 491 to the IPC gate has been released. 492 493 When a client program terminates, its references to capabilities should be 494 released, and this should cause a reference counter associated with the IPC 495 gate to decrement. Upon the loss of the final reference and the delivery of 496 the interrupt, the server framework will call a `close` method on the 497 `Resource` object concerned, this implementing the 498 [[ServerLibrary#Accountable|`Accountable`]] interface. 499 500 ######## A graph showing the closing mechanism 501 502 {{{#!graphviz 503 #format svg 504 #transform notugly 505 digraph closing { 506 node [fontsize="12.0",fontname="sans-serif",shape=box]; 507 edge [fontsize="12.0",fontname="sans-serif"]; 508 rankdir=LR; 509 510 Client [label="Client\nprogram"]; 511 512 subgraph { 513 rank=same; 514 515 Gate_note [shape=note,style=filled,fillcolor=gold,label="Actual\nendpoint"]; 516 Gate [label="IPC gate",shape="octagon"]; 517 IRQ [shape="triangle"]; 518 ResourceServer; 519 ResourceServer_note [shape=note,style=filled,fillcolor=gold,label="Handles\nrequests"]; 520 521 Gate_note -> Gate [dir=none,style=dotted]; 522 ResourceServer -> ResourceServer_note [dir=none,style=dotted]; 523 } 524 525 Resource [label="Resource\n(Pager)"]; 526 527 Provider; 528 529 ProviderRegistry; 530 531 Client -> Gate [style=dashed,label="(release)"]; 532 Gate -> IRQ -> ResourceServer; 533 ResourceServer -> Resource [label="close"]; 534 Resource -> Provider [label="notify_others\nunsubscribe"]; 535 Resource -> ProviderRegistry [label="detach"]; 536 ProviderRegistry -> Provider [label="detach\ndelete"]; 537 } 538 }}} 539 540 ######## 541 542 As a consequence of closing a file, an `unsubscribe` operation performed on 543 the `Provider` should cause any `Notifier` objects associated with the 544 `Resource` object to be released. Meanwhile, the `ResourceServer` will discard 545 the `Resource` object before the server thread terminates. 546 547 == Removing Files == 548 549 Unix filesystem semantics typically allow a file to be "unlinked" while still 550 being accessed by a program, with accesses still being directed to the file, 551 but with the file being removed from a directory and potentially being 552 replaced by another file. To support this, a mechanism is provided to defer 553 any removal of an open file. 554 555 ######## A graph showing the removal mechanism 556 557 {{{#!graphviz 558 #format svg 559 #transform notugly 560 digraph removing { 561 node [fontsize="12.0",fontname="sans-serif",shape=box]; 562 edge [fontsize="12.0",fontname="sans-serif"]; 563 rankdir=LR; 564 565 subgraph { 566 rank=same; 567 568 Client1_note [shape=note,style=filled,fillcolor=gold,label="Removing\nopen file"]; 569 Client1 [label="Client\nprogram"]; 570 Client2 [label="Client\nprogram"]; 571 Client2_note [shape=note,style=filled,fillcolor=gold,label="Closes\nopen file"]; 572 573 Client1_note -> Client1 [dir=none,style=dotted]; 574 Client2 -> Client2_note [dir=none,style=dotted]; 575 576 Client1 -> Client2 [dir=none,style=invis]; 577 } 578 579 subgraph { 580 rank=same; 581 582 Resource [label="Resource\n(Pager)"]; 583 Opener; 584 } 585 586 subgraph { 587 rank=same; 588 589 Provider1 [label="Provider"]; 590 Provider1_note [shape=note,style=filled,fillcolor=gold,label="Maintains\nremoval\nstate"]; 591 Provider2 [label="Provider"]; 592 593 Provider1 -> Provider1_note -> Provider2 [dir=none,style=dotted]; 594 } 595 596 ProviderRegistry1 [label="ProviderRegistry"]; 597 ProviderRegistry2 [label="ProviderRegistry"]; 598 599 subgraph { 600 rank=same; 601 602 FileOpening; 603 Accessor_note [shape=note,style=filled,fillcolor=gold,label="Performing\nfilesystem\noperations"]; 604 Accessor; 605 606 FileOpening -> Accessor_note -> Accessor [dir=none,style=dotted]; 607 } 608 609 /* Removing the file while it remains open. */ 610 611 Client1 -> Opener [label="remove\n(via context)"]; 612 Opener -> ResourceRegistry [label="remove_provider"]; 613 ResourceRegistry -> FileOpening [label="get_fileid\nunlink_object"]; 614 ResourceRegistry -> ProviderRegistry1 [label="get(fileid)"]; 615 ResourceRegistry -> Provider1 [label="remove_pending"]; 616 617 /* File closure and deferred removal. */ 618 619 Client2 -> Resource [label="close"]; 620 Resource -> Provider2 [label="notify_others\nunsubscribe"]; 621 Resource -> ProviderRegistry2 [label="detach"]; 622 ProviderRegistry2 -> Provider2 [label="remove"]; 623 Provider2 -> Accessor [label="remove"]; 624 } 625 }}} 626 627 ########