L4Re/departure

docs/wiki/FilesystemAccess

391:bc65615a8fed
2022-06-30 Paul Boddie Added missing structure members. mmap-region-flags
     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 ########