source: mainline/uspace/srv/vfs/vfs_lookup.c@ 09d5ec8

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 09d5ec8 was df908b3, checked in by Jakub Jermar <jakub@…>, 15 years ago

Use async relations introduced in the previous changeset to implement
vfs_grab_phone() and vfs_release_phone().

With this change, VFS will not be pointlessly connecting and disconnecting
phones on each VFS request.

Judging from the output of the top utility, this reduces the share of VFS on
kernel time by about 7% (from 25% down to 18%) and DEVFS kernel time by about 5%
(from 28% to 23%). This also makes CONSOLE the biggest consumer of kernel time,
while it used to be third after DEVFS and VFS.

  • Property mode set to 100644
File size: 6.1 KB
RevLine 
[62da45a]1/*
2 * Copyright (c) 2008 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup fs
30 * @{
[05b9912]31 */
[62da45a]32
33/**
[05b9912]34 * @file vfs_lookup.c
[62da45a]35 * @brief
36 */
37
[dadcec1]38#include "vfs.h"
[62da45a]39#include <ipc/ipc.h>
[ed903174]40#include <macros.h>
[62da45a]41#include <async.h>
42#include <errno.h>
[19f857a]43#include <str.h>
[a8e9ab8d]44#include <stdarg.h>
[62da45a]45#include <bool.h>
[1e4cada]46#include <fibril_synch.h>
[d9c8c81]47#include <adt/list.h>
[dadcec1]48#include <vfs/canonify.h>
[62da45a]49
[05b9912]50#define min(a, b) ((a) < (b) ? (a) : (b))
[62da45a]51
[553492be]52FIBRIL_MUTEX_INITIALIZE(plb_mutex);
[7b47fa2]53LIST_INITIALIZE(plb_head); /**< PLB entry ring buffer. */
[62da45a]54uint8_t *plb = NULL;
55
56/** Perform a path lookup.
57 *
[05b9912]58 * @param path Path to be resolved; it must be a NULL-terminated
59 * string.
60 * @param lflag Flags to be used during lookup.
61 * @param result Empty structure where the lookup result will be stored.
62 * Can be NULL.
63 * @param altroot If non-empty, will be used instead of rootfs as the root
64 * of the whole VFS tree.
65 *
66 * @return EOK on success or an error code from errno.h.
[62da45a]67 *
68 */
[d6084ef]69int vfs_lookup_internal(char *path, int lflag, vfs_lookup_res_t *result,
[a8e9ab8d]70 vfs_pair_t *altroot, ...)
[62da45a]71{
72 vfs_pair_t *root;
73
74 if (altroot)
75 root = altroot;
76 else
[f49b0ea]77 root = &rootfs;
[62da45a]78
79 if (!root->fs_handle)
80 return ENOENT;
81
[d6084ef]82 size_t len;
83 path = canonify(path, &len);
84 if (!path)
85 return EINVAL;
86
[f2ec8c8]87 fs_index_t index = 0;
[a8e9ab8d]88 if (lflag & L_LINK) {
89 va_list ap;
90
91 va_start(ap, altroot);
[f2ec8c8]92 index = va_arg(ap, fs_index_t);
[a8e9ab8d]93 va_end(ap);
94 }
95
[553492be]96 fibril_mutex_lock(&plb_mutex);
[62da45a]97
98 plb_entry_t entry;
99 link_initialize(&entry.plb_link);
100 entry.len = len;
101
[ed903174]102 size_t first; /* the first free index */
103 size_t last; /* the last free index */
[62da45a]104
105 if (list_empty(&plb_head)) {
106 first = 0;
107 last = PLB_SIZE - 1;
108 } else {
109 plb_entry_t *oldest = list_get_instance(plb_head.next,
110 plb_entry_t, plb_link);
111 plb_entry_t *newest = list_get_instance(plb_head.prev,
112 plb_entry_t, plb_link);
113
114 first = (newest->index + newest->len) % PLB_SIZE;
115 last = (oldest->index - 1) % PLB_SIZE;
116 }
117
118 if (first <= last) {
119 if ((last - first) + 1 < len) {
120 /*
121 * The buffer cannot absorb the path.
122 */
[553492be]123 fibril_mutex_unlock(&plb_mutex);
[62da45a]124 return ELIMIT;
125 }
126 } else {
127 if (PLB_SIZE - ((first - last) + 1) < len) {
128 /*
129 * The buffer cannot absorb the path.
130 */
[553492be]131 fibril_mutex_unlock(&plb_mutex);
[62da45a]132 return ELIMIT;
133 }
134 }
135
136 /*
137 * We know the first free index in PLB and we also know that there is
138 * enough space in the buffer to hold our path.
139 */
140
141 entry.index = first;
142 entry.len = len;
143
144 /*
145 * Claim PLB space by inserting the entry into the PLB entry ring
146 * buffer.
147 */
148 list_append(&entry.plb_link, &plb_head);
149
[553492be]150 fibril_mutex_unlock(&plb_mutex);
[62da45a]151
152 /*
153 * Copy the path into PLB.
154 */
155 size_t cnt1 = min(len, (PLB_SIZE - first) + 1);
156 size_t cnt2 = len - cnt1;
157
158 memcpy(&plb[first], path, cnt1);
159 memcpy(plb, &path[cnt1], cnt2);
160
161 ipc_call_t answer;
162 int phone = vfs_grab_phone(root->fs_handle);
[4198f9c3]163 aid_t req = async_send_5(phone, VFS_OUT_LOOKUP, (ipcarg_t) first,
[62da45a]164 (ipcarg_t) (first + len - 1) % PLB_SIZE,
[a8e9ab8d]165 (ipcarg_t) root->dev_handle, (ipcarg_t) lflag, (ipcarg_t) index,
166 &answer);
[50461f2]167
[62da45a]168 ipcarg_t rc;
169 async_wait_for(req, &rc);
[df908b3]170 vfs_release_phone(root->fs_handle, phone);
[50461f2]171
[553492be]172 fibril_mutex_lock(&plb_mutex);
[62da45a]173 list_remove(&entry.plb_link);
174 /*
175 * Erasing the path from PLB will come handy for debugging purposes.
176 */
177 memset(&plb[first], 0, cnt1);
178 memset(plb, 0, cnt2);
[553492be]179 fibril_mutex_unlock(&plb_mutex);
[ed903174]180
181 if (((int) rc < EOK) || (!result))
182 return (int) rc;
183
184 result->triplet.fs_handle = (fs_handle_t) rc;
185 result->triplet.dev_handle = (dev_handle_t) IPC_GET_ARG1(answer);
186 result->triplet.index = (fs_index_t) IPC_GET_ARG2(answer);
187 result->size =
188 (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(answer), IPC_GET_ARG4(answer));
189 result->lnkcnt = (unsigned int) IPC_GET_ARG5(answer);
190
191 if (lflag & L_FILE)
192 result->type = VFS_NODE_FILE;
193 else if (lflag & L_DIRECTORY)
194 result->type = VFS_NODE_DIRECTORY;
195 else
196 result->type = VFS_NODE_UNKNOWN;
197
198 return EOK;
[62da45a]199}
200
[05b9912]201/** Perform a node open operation.
202 *
203 * @return EOK on success or an error code from errno.h.
204 *
205 */
206int vfs_open_node_internal(vfs_lookup_res_t *result)
207{
208 int phone = vfs_grab_phone(result->triplet.fs_handle);
209
210 ipc_call_t answer;
[4198f9c3]211 aid_t req = async_send_2(phone, VFS_OUT_OPEN_NODE,
[05b9912]212 (ipcarg_t) result->triplet.dev_handle,
213 (ipcarg_t) result->triplet.index, &answer);
214
215 ipcarg_t rc;
216 async_wait_for(req, &rc);
[df908b3]217 vfs_release_phone(result->triplet.fs_handle, phone);
[05b9912]218
219 if (rc == EOK) {
[ed903174]220 result->size =
221 MERGE_LOUP32(IPC_GET_ARG1(answer), IPC_GET_ARG2(answer));
222 result->lnkcnt = (unsigned int) IPC_GET_ARG3(answer);
223 if (IPC_GET_ARG4(answer) & L_FILE)
[05b9912]224 result->type = VFS_NODE_FILE;
[ed903174]225 else if (IPC_GET_ARG4(answer) & L_DIRECTORY)
[05b9912]226 result->type = VFS_NODE_DIRECTORY;
227 else
228 result->type = VFS_NODE_UNKNOWN;
229 }
230
231 return rc;
232}
233
[62da45a]234/**
235 * @}
[9bb85f3]236 */
Note: See TracBrowser for help on using the repository browser.