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