L4Re/departure

libfsserver/lib/directories/directory_resource.cc

267:1e0103025bbb
2022-03-02 Paul Boddie Employ capability discarding instead of a completion operation. This may not actually fix the weird race condition that has occurred where the reader capability seems to be freed before it can be discarded from the task, causing an annoying assertion error in the L4Re counting capability allocator.
     1 /*     2  * A resource offering support for accessing directories.     3  *     4  * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>     5  *     6  * This program is free software; you can redistribute it and/or     7  * modify it under the terms of the GNU General Public License as     8  * published by the Free Software Foundation; either version 2 of     9  * the License, or (at your option) any later version.    10  *    11  * This program is distributed in the hope that it will be useful,    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    14  * GNU General Public License for more details.    15  *    16  * You should have received a copy of the GNU General Public License    17  * along with this program; if not, write to the Free Software    18  * Foundation, Inc., 51 Franklin Street, Fifth Floor,    19  * Boston, MA  02110-1301, USA    20  */    21     22 #include <thread>    23     24 #include <fsclient/client.h>    25 #include <ipc/cap_alloc.h>    26     27 #include "directory_resource.h"    28 #include "directory_object_server.h"    29     30     31     32 DirectoryResource::DirectoryResource(fileid_t fileid,    33                                      DirectoryProvider *provider)    34 : _provider(provider), fileid(fileid)    35 {    36 }    37     38 DirectoryResource::~DirectoryResource()    39 {    40 }    41     42     43     44 int DirectoryResource::expected_items()    45 {    46     return DirectoryObject_expected_items;    47 }    48     49 ipc_server_handler_type DirectoryResource::handler()    50 {    51     return (ipc_server_handler_type) handle_DirectoryObject;    52 }    53     54     55     56 /* Close the resource, removing the provider from the registry if    57    appropriate. */    58     59 void DirectoryResource::close()    60 {       61     /* Detach the resource, potentially removing the file provider. */    62         63     _provider->registry()->detach(fileid, _provider);    64 }    65     66     67     68 /* Thread payload for directory listing production. */    69     70 static void read_directory(DirectoryProvider *provider, fileid_t fileid,    71                            file_t *writer)    72 {    73     DirectoryAccessor *accessor = provider->accessor();    74     75     /* Invoke the directory reading mechanism. */    76     77     accessor->read_directory(writer);    78     79     /* Close and detach from the registry. */    80     81     client_close(writer);    82     provider->registry()->detach(fileid, provider);    83 }    84     85     86     87 /* Open a directory to read the directory entries via a file-like object. */    88     89 long DirectoryResource::opendir(offset_t *size, l4_cap_idx_t *file,    90                                 object_flags_t *object_flags)    91 {    92     file_t *reader, *writer;    93     94     /* Mapping of the reader's memory region should be avoided because no use    95        of the reader will be made here. */    96     97     long err = client_pipe(&reader, &writer, 0);    98     99     if (err)   100         return err;   101    102     *size = reader->size;   103     *file = discard_cap(reader->ref);   104     *object_flags = 0;      /* does not support mmap, has no fixed size */   105    106     /* Discard the reader structure but preserve the capability. */   107    108     reader->ref = L4_INVALID_CAP;   109     file_close(reader);   110    111     /* Attach to the provider to keep it available, even if the directory   112        resource is released. */   113    114     _provider->attach();   115    116     /* Initiate the reading process. */   117    118     std::thread(read_directory, _provider, fileid, writer).detach();   119    120     /* Send the capability immediately, discarding it afterwards. */   121    122     return L4_EOK;   123 }   124    125    126    127 /* NOTE: These methods are effectively the same as the FilePager methods. */   128    129 /* Subscribe to notifications. */   130    131 long DirectoryResource::subscribe(l4_cap_idx_t endpoint, notify_flags_t flags)   132 {   133     _endpoint = _provider->subscribe(endpoint, flags);   134     return L4_EOK;   135 }   136    137 long DirectoryResource::unsubscribe(l4_cap_idx_t endpoint)   138 {   139     _provider->unsubscribe(_endpoint, endpoint);   140     return L4_EOK;   141 }   142    143 // vim: tabstop=4 expandtab shiftwidth=4