L4Re/departure

Annotated libfsserver/lib/directories/directory_resource.cc

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