00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00038 #include <ipc/services.h>
00039 #include <async.h>
00040 #include <fibril.h>
00041 #include <fibril_synch.h>
00042 #include <errno.h>
00043 #include <stdio.h>
00044 #include <stdlib.h>
00045 #include <str.h>
00046 #include <ctype.h>
00047 #include <bool.h>
00048 #include <adt/list.h>
00049 #include <as.h>
00050 #include <assert.h>
00051 #include <atomic.h>
00052 #include "vfs.h"
00053
00054 FIBRIL_CONDVAR_INITIALIZE(fs_head_cv);
00055 FIBRIL_MUTEX_INITIALIZE(fs_head_lock);
00056 LIST_INITIALIZE(fs_head);
00057
00058 atomic_t fs_handle_next = {
00059 .count = 1
00060 };
00061
00068 static bool vfs_info_sane(vfs_info_t *info)
00069 {
00070 int i;
00071
00072
00073
00074
00075
00076 if (!islower(info->name[0])) {
00077 dprintf("The name doesn't start with a lowercase character.\n");
00078 return false;
00079 }
00080 for (i = 1; i < FS_NAME_MAXLEN; i++) {
00081 if (!(islower(info->name[i]) || isdigit(info->name[i])) &&
00082 (info->name[i] != '-') && (info->name[i] != '_')) {
00083 if (info->name[i] == '\0') {
00084 break;
00085 } else {
00086 dprintf("The name contains illegal "
00087 "characters.\n");
00088 return false;
00089 }
00090 }
00091 }
00092
00093
00094
00095
00096 if (info->name[i] != '\0') {
00097 dprintf("The name is not properly NULL-terminated.\n");
00098 return false;
00099 }
00100
00101 return true;
00102 }
00103
00109 void vfs_register(ipc_callid_t rid, ipc_call_t *request)
00110 {
00111 int phone;
00112
00113 dprintf("Processing VFS_REGISTER request received from %p.\n",
00114 request->in_phone_hash);
00115
00116 vfs_info_t *vfs_info;
00117 int rc = async_data_write_accept((void **) &vfs_info, false,
00118 sizeof(vfs_info_t), sizeof(vfs_info_t), 0, NULL);
00119
00120 if (rc != EOK) {
00121 dprintf("Failed to deliver the VFS info into our AS, rc=%d.\n",
00122 rc);
00123 async_answer_0(rid, rc);
00124 return;
00125 }
00126
00127
00128
00129
00130 fs_info_t *fs_info = (fs_info_t *) malloc(sizeof(fs_info_t));
00131 if (!fs_info) {
00132 dprintf("Could not allocate memory for FS info.\n");
00133 async_answer_0(rid, ENOMEM);
00134 return;
00135 }
00136
00137 link_initialize(&fs_info->fs_link);
00138 fs_info->vfs_info = *vfs_info;
00139 free(vfs_info);
00140
00141 dprintf("VFS info delivered.\n");
00142
00143 if (!vfs_info_sane(&fs_info->vfs_info)) {
00144 free(fs_info);
00145 async_answer_0(rid, EINVAL);
00146 return;
00147 }
00148
00149 fibril_mutex_lock(&fs_head_lock);
00150
00151
00152
00153
00154 if (fs_name_to_handle(fs_info->vfs_info.name, false)) {
00155
00156
00157
00158 dprintf("FS is already registered.\n");
00159 fibril_mutex_unlock(&fs_head_lock);
00160 free(fs_info);
00161 async_answer_0(rid, EEXISTS);
00162 return;
00163 }
00164
00165
00166
00167
00168 dprintf("Inserting FS into the list of registered file systems.\n");
00169 list_append(&fs_info->fs_link, &fs_head);
00170
00171
00172
00173
00174
00175
00176 ipc_call_t call;
00177 ipc_callid_t callid = async_get_call(&call);
00178 if (IPC_GET_IMETHOD(call) != IPC_M_CONNECT_TO_ME) {
00179 dprintf("Unexpected call, method = %d\n", IPC_GET_IMETHOD(call));
00180 list_remove(&fs_info->fs_link);
00181 fibril_mutex_unlock(&fs_head_lock);
00182 free(fs_info);
00183 async_answer_0(callid, EINVAL);
00184 async_answer_0(rid, EINVAL);
00185 return;
00186 }
00187
00188 phone = IPC_GET_ARG5(call);
00189 async_session_create(&fs_info->session, phone, 0);
00190 async_answer_0(callid, EOK);
00191
00192 dprintf("Callback connection to FS created.\n");
00193
00194
00195
00196
00197
00198 size_t size;
00199 if (!async_share_in_receive(&callid, &size)) {
00200 dprintf("Unexpected call, method = %d\n", IPC_GET_IMETHOD(call));
00201 list_remove(&fs_info->fs_link);
00202 fibril_mutex_unlock(&fs_head_lock);
00203 async_session_destroy(&fs_info->session);
00204 async_hangup(phone);
00205 free(fs_info);
00206 async_answer_0(callid, EINVAL);
00207 async_answer_0(rid, EINVAL);
00208 return;
00209 }
00210
00211
00212
00213
00214 if (size != PLB_SIZE) {
00215 dprintf("Client suggests wrong size of PFB, size = %d\n", size);
00216 list_remove(&fs_info->fs_link);
00217 fibril_mutex_unlock(&fs_head_lock);
00218 async_session_destroy(&fs_info->session);
00219 async_hangup(phone);
00220 free(fs_info);
00221 async_answer_0(callid, EINVAL);
00222 async_answer_0(rid, EINVAL);
00223 return;
00224 }
00225
00226
00227
00228
00229 (void) async_share_in_finalize(callid, plb,
00230 AS_AREA_READ | AS_AREA_CACHEABLE);
00231
00232 dprintf("Sharing PLB.\n");
00233
00234
00235
00236
00237
00238
00239 fs_info->fs_handle = (fs_handle_t) atomic_postinc(&fs_handle_next);
00240 async_answer_1(rid, EOK, (sysarg_t) fs_info->fs_handle);
00241
00242 fibril_condvar_broadcast(&fs_head_cv);
00243 fibril_mutex_unlock(&fs_head_lock);
00244
00245 dprintf("\"%.*s\" filesystem successfully registered, handle=%d.\n",
00246 FS_NAME_MAXLEN, fs_info->vfs_info.name, fs_info->fs_handle);
00247 }
00248
00256 int vfs_grab_phone(fs_handle_t handle)
00257 {
00258 link_t *cur;
00259 fs_info_t *fs;
00260 int phone;
00261
00262
00263
00264
00265
00266
00267
00268
00269 fibril_mutex_lock(&fs_head_lock);
00270 for (cur = fs_head.next; cur != &fs_head; cur = cur->next) {
00271 fs = list_get_instance(cur, fs_info_t, fs_link);
00272 if (fs->fs_handle == handle) {
00273 fibril_mutex_unlock(&fs_head_lock);
00274 phone = async_exchange_begin(&fs->session);
00275
00276 assert(phone > 0);
00277 return phone;
00278 }
00279 }
00280 fibril_mutex_unlock(&fs_head_lock);
00281 return 0;
00282 }
00283
00288 void vfs_release_phone(fs_handle_t handle, int phone)
00289 {
00290 link_t *cur;
00291 fs_info_t *fs;
00292
00293 fibril_mutex_lock(&fs_head_lock);
00294 for (cur = fs_head.next; cur != &fs_head; cur = cur->next) {
00295 fs = list_get_instance(cur, fs_info_t, fs_link);
00296 if (fs->fs_handle == handle) {
00297 fibril_mutex_unlock(&fs_head_lock);
00298 async_exchange_end(&fs->session, phone);
00299 return;
00300 }
00301 }
00302
00303 abort();
00304 fibril_mutex_unlock(&fs_head_lock);
00305 }
00306
00315 fs_handle_t fs_name_to_handle(char *name, bool lock)
00316 {
00317 int handle = 0;
00318
00319 if (lock)
00320 fibril_mutex_lock(&fs_head_lock);
00321 link_t *cur;
00322 for (cur = fs_head.next; cur != &fs_head; cur = cur->next) {
00323 fs_info_t *fs = list_get_instance(cur, fs_info_t, fs_link);
00324 if (str_cmp(fs->vfs_info.name, name) == 0) {
00325 handle = fs->fs_handle;
00326 break;
00327 }
00328 }
00329 if (lock)
00330 fibril_mutex_unlock(&fs_head_lock);
00331 return handle;
00332 }
00333
00339 vfs_info_t *fs_handle_to_info(fs_handle_t handle)
00340 {
00341 vfs_info_t *info = NULL;
00342 link_t *cur;
00343
00344 fibril_mutex_lock(&fs_head_lock);
00345 for (cur = fs_head.next; cur != &fs_head; cur = cur->next) {
00346 fs_info_t *fs = list_get_instance(cur, fs_info_t, fs_link);
00347 if (fs->fs_handle == handle) {
00348 info = &fs->vfs_info;
00349 break;
00350 }
00351 }
00352 fibril_mutex_unlock(&fs_head_lock);
00353
00354 return info;
00355 }
00356