Changeset 4636a60 in mainline
- Timestamp:
- 2013-07-30T22:54:10Z (11 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 06256b0
- Parents:
- 5bcd5b7
- Location:
- uspace
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/vfs/vfs.c
r5bcd5b7 r4636a60 260 260 } 261 261 262 /* Ask VFS whether it likes fs_name. */263 rc = async_req_0_0(exch, VFS_IN_PING);264 if (rc != EOK) {265 vfs_exchange_end(exch);266 free(mpa);267 async_wait_for(req, &rc_orig);268 269 if (null_id != -1)270 loc_null_destroy(null_id);271 272 if (rc_orig == EOK)273 return (int) rc;274 else275 return (int) rc_orig;276 }277 278 262 vfs_exchange_end(exch); 279 263 free(mpa); -
uspace/srv/vfs/vfs_ops.c
r5bcd5b7 r4636a60 70 70 vfs_node_t *root = NULL; 71 71 72 #if 0 73 static int vfs_attach_internal(vfs_node_t *mpoint, vfs_node_t *mountee) 74 { 75 assert(mpoint != NULL); 76 assert(mountee != NULL); 77 78 if (mpoint->mount != NULL) { 79 return EBUSY; 80 } 81 82 if (mpoint->type != VFS_NODE_DIRECTORY) { 83 return ENOTDIR; 84 } 85 86 if (vfs_node_has_children(mpoint)) { 87 return ENOTEMPTY; 88 } 89 90 mpoint->mount = mountee; 91 vfs_node_addref(mountee); 92 /* Add reference to make sure the node is not freed. Removed in detach_internal(). */ 93 vfs_node_addref(mpoint); 72 static int vfs_connect_internal(service_id_t service_id, unsigned flags, unsigned instance, 73 char *options, char *fsname, vfs_node_t **root) 74 { 75 fs_handle_t fs_handle = 0; 76 77 fibril_mutex_lock(&fs_list_lock); 78 while (1) { 79 fs_handle = fs_name_to_handle(instance, fsname, false); 80 81 if (fs_handle != 0 || !(flags & IPC_FLAG_BLOCKING)) { 82 break; 83 } 84 85 fibril_condvar_wait(&fs_list_cv, &fs_list_lock); 86 } 87 fibril_mutex_unlock(&fs_list_lock); 88 89 if (fs_handle == 0) { 90 return ENOENT; 91 } 92 93 /* Tell the mountee that it is being mounted. */ 94 ipc_call_t answer; 95 async_exch_t *exch = vfs_exchange_grab(fs_handle); 96 aid_t msg = async_send_1(exch, VFS_OUT_MOUNTED, (sysarg_t) service_id, &answer); 97 /* Send the mount options */ 98 sysarg_t rc = async_data_write_start(exch, options, str_size(options)); 99 if (rc != EOK) { 100 async_forget(msg); 101 vfs_exchange_release(exch); 102 return rc; 103 } 104 async_wait_for(msg, &rc); 105 vfs_exchange_release(exch); 106 107 if (rc != EOK) { 108 return rc; 109 } 110 111 vfs_lookup_res_t res; 112 res.triplet.fs_handle = fs_handle; 113 res.triplet.service_id = service_id; 114 res.triplet.index = (fs_index_t) IPC_GET_ARG1(answer); 115 res.size = (int64_t) MERGE_LOUP32(IPC_GET_ARG2(answer), IPC_GET_ARG3(answer)); 116 res.type = VFS_NODE_DIRECTORY; 117 118 /* Add reference to the mounted root. */ 119 *root = vfs_node_get(&res); 120 assert(*root); 121 94 122 return EOK; 95 123 } 96 124 97 static int vfs_detach_internal(vfs_node_t *mpoint) 98 { 99 assert(mpoint != NULL); 100 101 if (mpoint->mount == NULL) { 102 return ENOENT; 103 } 104 vfs_node_put(mpoint->mount); 105 mpoint->mount = NULL; 106 vfs_node_put(mpoint); 107 } 108 #endif 109 110 static int vfs_mount_internal(ipc_callid_t rid, service_id_t service_id, 111 fs_handle_t fs_handle, char *mp, char *opts) 112 { 113 vfs_lookup_res_t mp_res; 114 vfs_lookup_res_t mr_res; 115 vfs_node_t *mp_node = NULL; 116 vfs_node_t *mr_node; 117 fs_index_t rindex; 118 aoff64_t rsize; 119 async_exch_t *exch; 120 sysarg_t rc; 121 aid_t msg; 122 ipc_call_t answer; 123 125 static int vfs_mount_internal(service_id_t service_id, unsigned flags, unsigned instance, 126 char *opts, char *fs_name, char *mp) 127 { 124 128 /* Resolve the path to the mountpoint. */ 125 fibril_rwlock_write_lock(&namespace_rwlock);129 126 130 if (root == NULL) { 127 131 /* We still don't have the root file system mounted. */ … … 131 135 * being mounted first. 132 136 */ 133 fibril_rwlock_write_unlock(&namespace_rwlock);134 async_answer_0(rid, ENOENT);135 137 return ENOENT; 136 138 } 137 139 138 /* 139 * For this simple, but important case, 140 * we are almost done. 141 */ 142 143 /* Tell the mountee that it is being mounted. */ 144 exch = vfs_exchange_grab(fs_handle); 145 msg = async_send_1(exch, VFS_OUT_MOUNTED, 146 (sysarg_t) service_id, &answer); 147 /* Send the mount options */ 148 rc = async_data_write_start(exch, (void *)opts, 149 str_size(opts)); 150 vfs_exchange_release(exch); 151 152 if (rc != EOK) { 153 async_forget(msg); 154 fibril_rwlock_write_unlock(&namespace_rwlock); 155 async_answer_0(rid, rc); 156 return rc; 157 } 158 async_wait_for(msg, &rc); 159 160 if (rc != EOK) { 161 fibril_rwlock_write_unlock(&namespace_rwlock); 162 async_answer_0(rid, rc); 163 return rc; 164 } 165 166 rindex = (fs_index_t) IPC_GET_ARG1(answer); 167 rsize = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG2(answer), 168 IPC_GET_ARG3(answer)); 169 170 mr_res.triplet.fs_handle = fs_handle; 171 mr_res.triplet.service_id = service_id; 172 mr_res.triplet.index = rindex; 173 mr_res.size = rsize; 174 mr_res.type = VFS_NODE_DIRECTORY; 175 176 /* Add reference to the mounted root. */ 177 root = vfs_node_get(&mr_res); 178 assert(root); 179 180 fibril_rwlock_write_unlock(&namespace_rwlock); 181 async_answer_0(rid, rc); 182 return rc; 140 return vfs_connect_internal(service_id, flags, instance, opts, fs_name, &root); 183 141 } 184 142 … … 186 144 if (str_cmp(mp, "/") == 0) { 187 145 /* Trying to mount root FS over root FS */ 188 fibril_rwlock_write_unlock(&namespace_rwlock);189 async_answer_0(rid, EBUSY);190 146 return EBUSY; 191 147 } 192 148 193 rc = vfs_lookup_internal(root, mp, L_DIRECTORY, &mp_res); 149 vfs_lookup_res_t mp_res; 150 int rc = vfs_lookup_internal(root, mp, L_DIRECTORY, &mp_res); 194 151 if (rc != EOK) { 195 152 /* The lookup failed. */ 196 fibril_rwlock_write_unlock(&namespace_rwlock);197 async_answer_0(rid, rc);198 153 return rc; 199 154 } 200 155 156 vfs_node_t *mp_node; 201 157 mp_node = vfs_node_get(&mp_res); 202 158 if (!mp_node) { 203 fibril_rwlock_write_unlock(&namespace_rwlock);204 async_answer_0(rid, ENOMEM);205 159 return ENOMEM; 206 160 } 207 161 208 /* 209 * Now we hold a reference to mp_node. 210 * It will be dropped upon the corresponding VFS_IN_UNMOUNT. 211 * This prevents the mount point from being deleted. 212 */ 213 214 /* 215 * At this point, we have all necessary pieces: file system handle 216 * and service ID, and we know the mount point VFS node. 217 */ 218 219 async_exch_t *mountee_exch = vfs_exchange_grab(fs_handle); 220 assert(mountee_exch); 221 222 exch = vfs_exchange_grab(mp_res.triplet.fs_handle); 223 msg = async_send_4(exch, VFS_OUT_MOUNT, 224 (sysarg_t) mp_res.triplet.service_id, 225 (sysarg_t) mp_res.triplet.index, 226 (sysarg_t) fs_handle, 227 (sysarg_t) service_id, &answer); 228 229 /* Send connection */ 230 rc = async_exchange_clone(exch, mountee_exch); 231 vfs_exchange_release(mountee_exch); 232 233 if (rc != EOK) { 234 vfs_exchange_release(exch); 235 async_forget(msg); 236 237 /* Mount failed, drop reference to mp_node. */ 238 if (mp_node) 239 vfs_node_put(mp_node); 240 241 async_answer_0(rid, rc); 242 fibril_rwlock_write_unlock(&namespace_rwlock); 243 return rc; 244 } 245 246 /* send the mount options */ 247 rc = async_data_write_start(exch, (void *) opts, str_size(opts)); 248 if (rc != EOK) { 249 vfs_exchange_release(exch); 250 async_forget(msg); 251 252 /* Mount failed, drop reference to mp_node. */ 253 if (mp_node) 254 vfs_node_put(mp_node); 255 256 fibril_rwlock_write_unlock(&namespace_rwlock); 257 async_answer_0(rid, rc); 258 return rc; 259 } 260 261 /* 262 * Wait for the answer before releasing the exchange to avoid deadlock 263 * in case the answer depends on further calls to the same file system. 264 * Think of a case when mounting a FS on a file_bd backed by a file on 265 * the same FS. 266 */ 267 async_wait_for(msg, &rc); 268 vfs_exchange_release(exch); 269 270 if (rc == EOK) { 271 rindex = (fs_index_t) IPC_GET_ARG1(answer); 272 rsize = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG2(answer), 273 IPC_GET_ARG3(answer)); 274 275 mr_res.triplet.fs_handle = fs_handle; 276 mr_res.triplet.service_id = service_id; 277 mr_res.triplet.index = rindex; 278 mr_res.size = rsize; 279 mr_res.type = VFS_NODE_DIRECTORY; 280 281 /* Add reference to the mounted root. */ 282 mr_node = vfs_node_get(&mr_res); 283 assert(mr_node); 284 } else { 285 /* Mount failed, drop reference to mp_node. */ 286 if (mp_node) 287 vfs_node_put(mp_node); 288 } 289 290 async_answer_0(rid, rc); 291 fibril_rwlock_write_unlock(&namespace_rwlock); 292 return rc; 162 if (mp_node->mount != NULL) { 163 return EBUSY; 164 } 165 166 if (mp_node->type != VFS_NODE_DIRECTORY) { 167 return ENOTDIR; 168 } 169 170 if (vfs_node_has_children(mp_node)) { 171 return ENOTEMPTY; 172 } 173 174 vfs_node_t *mountee; 175 176 rc = vfs_connect_internal(service_id, flags, instance, opts, fs_name, &mountee); 177 if (rc != EOK) { 178 vfs_node_put(mp_node); 179 return ENOMEM; 180 } 181 182 mp_node->mount = mountee; 183 /* The two references to nodes are held by the mount so that they cannot be freed. 184 * They are removed in detach_internal(). 185 */ 186 return EOK; 293 187 } 294 188 295 189 void vfs_mount(ipc_callid_t rid, ipc_call_t *request) 296 190 { 297 service_id_t service_id;298 299 191 /* 300 192 * We expect the library to do the device-name to device-handle … … 302 194 * in the request. 303 195 */ 304 service_id = (service_id_t) IPC_GET_ARG1(*request);196 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*request); 305 197 306 198 /* … … 328 220 0, NULL); 329 221 if (rc != EOK) { 222 async_answer_0(rid, rc); 330 223 free(mp); 331 async_answer_0(rid, rc);332 224 return; 333 225 } … … 341 233 FS_NAME_MAXLEN, 0, NULL); 342 234 if (rc != EOK) { 235 async_answer_0(rid, rc); 343 236 free(mp); 344 237 free(opts); 345 async_answer_0(rid, rc); 346 return; 347 } 348 349 /* 350 * Wait for VFS_IN_PING so that we can return an error if we don't know 351 * fs_name. 352 */ 353 ipc_call_t data; 354 ipc_callid_t callid = async_get_call(&data); 355 if (IPC_GET_IMETHOD(data) != VFS_IN_PING) { 356 async_answer_0(callid, ENOTSUP); 357 async_answer_0(rid, ENOTSUP); 358 free(mp); 359 free(opts); 360 free(fs_name); 361 return; 362 } 363 364 /* 365 * Check if we know a file system with the same name as is in fs_name. 366 * This will also give us its file system handle. 367 */ 368 fibril_mutex_lock(&fs_list_lock); 369 fs_handle_t fs_handle; 370 recheck: 371 fs_handle = fs_name_to_handle(instance, fs_name, false); 372 if (!fs_handle) { 373 if (flags & IPC_FLAG_BLOCKING) { 374 fibril_condvar_wait(&fs_list_cv, &fs_list_lock); 375 goto recheck; 376 } 377 378 fibril_mutex_unlock(&fs_list_lock); 379 async_answer_0(callid, ENOENT); 380 async_answer_0(rid, ENOENT); 381 free(mp); 382 free(fs_name); 383 free(opts); 384 return; 385 } 386 fibril_mutex_unlock(&fs_list_lock); 387 238 return; 239 } 240 388 241 /* Add the filesystem info to the list of mounted filesystems */ 389 242 mtab_ent_t *mtab_ent = malloc(sizeof(mtab_ent_t)); 390 243 if (!mtab_ent) { 391 async_answer_0(callid, ENOMEM);392 244 async_answer_0(rid, ENOMEM); 393 245 free(mp); … … 396 248 return; 397 249 } 398 399 /* Do the mount */ 400 rc = vfs_mount_internal(rid, service_id, fs_handle, mp, opts); 401 if (rc != EOK) { 402 async_answer_0(callid, ENOTSUP); 403 async_answer_0(rid, ENOTSUP); 404 free(mtab_ent); 405 free(mp); 406 free(opts); 407 free(fs_name); 408 return; 409 } 250 251 /* Mount the filesystem. */ 252 fibril_rwlock_write_lock(&namespace_rwlock); 253 rc = vfs_mount_internal(service_id, flags, instance, opts, fs_name, mp); 254 fibril_rwlock_write_unlock(&namespace_rwlock); 410 255 411 256 /* Add the filesystem info to the list of mounted filesystems */ 412 413 str_cpy(mtab_ent->mp, MAX_PATH_LEN, mp); 414 str_cpy(mtab_ent->fs_name, FS_NAME_MAXLEN, fs_name); 415 str_cpy(mtab_ent->opts, MAX_MNTOPTS_LEN, opts); 416 mtab_ent->instance = instance; 417 mtab_ent->service_id = service_id; 418 419 link_initialize(&mtab_ent->link); 420 421 fibril_mutex_lock(&mtab_list_lock); 422 list_append(&mtab_ent->link, &mtab_list); 423 mtab_size++; 424 fibril_mutex_unlock(&mtab_list_lock); 257 if (rc == EOK) { 258 str_cpy(mtab_ent->mp, MAX_PATH_LEN, mp); 259 str_cpy(mtab_ent->fs_name, FS_NAME_MAXLEN, fs_name); 260 str_cpy(mtab_ent->opts, MAX_MNTOPTS_LEN, opts); 261 mtab_ent->instance = instance; 262 mtab_ent->service_id = service_id; 263 264 link_initialize(&mtab_ent->link); 265 266 fibril_mutex_lock(&mtab_list_lock); 267 list_append(&mtab_ent->link, &mtab_list); 268 mtab_size++; 269 fibril_mutex_unlock(&mtab_list_lock); 270 } 271 272 async_answer_0(rid, rc); 425 273 426 274 free(mp); 427 275 free(fs_name); 428 276 free(opts); 429 430 /* Acknowledge that we know fs_name. */431 async_answer_0(callid, EOK);432 277 } 433 278 434 279 void vfs_unmount(ipc_callid_t rid, ipc_call_t *request) 435 280 { 436 int rc; 281 /* 282 * Receive the mount point path. 283 */ 437 284 char *mp; 438 vfs_lookup_res_t mp_res; 439 vfs_lookup_res_t mr_res; 440 vfs_node_t *mr_node; 441 async_exch_t *exch; 442 443 /* 444 * Receive the mount point path. 445 */ 446 rc = async_data_write_accept((void **) &mp, true, 0, MAX_PATH_LEN, 285 int rc = async_data_write_accept((void **) &mp, true, 0, MAX_PATH_LEN, 447 286 0, NULL); 448 287 if (rc != EOK) … … 458 297 */ 459 298 fibril_rwlock_write_lock(&namespace_rwlock); 460 461 /* 462 * Lookup the mounted root and instantiate it. 463 */ 464 rc = vfs_lookup_internal(root, mp, 0, &mr_res); 465 if (rc != EOK) { 466 fibril_rwlock_write_unlock(&namespace_rwlock); 299 300 if (str_cmp(mp, "/") == 0) { 467 301 free(mp); 468 async_answer_0(rid, rc);469 return;470 }471 mr_node = vfs_node_get(&mr_res);472 if (!mr_node) {473 fibril_rwlock_write_unlock(&namespace_rwlock);474 free(mp);475 async_answer_0(rid, ENOMEM);476 return;477 }478 479 /*480 * Count the total number of references for the mounted file system. We481 * are expecting at least two. One which we got above and one which we482 * got when the file system was mounted. If we find more, it means that483 * the file system cannot be gracefully unmounted at the moment because484 * someone is working with it.485 */486 if (vfs_nodes_refcount_sum_get(mr_node->fs_handle,487 mr_node->service_id) != 2) {488 fibril_rwlock_write_unlock(&namespace_rwlock);489 vfs_node_put(mr_node);490 free(mp);491 async_answer_0(rid, EBUSY);492 return;493 }494 495 if (str_cmp(mp, "/") == 0) {496 302 497 303 /* … … 502 308 */ 503 309 504 exch = vfs_exchange_grab(mr_node->fs_handle); 505 rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED, 506 mr_node->service_id); 310 if (!root) { 311 fibril_rwlock_write_unlock(&namespace_rwlock); 312 async_answer_0(rid, ENOENT); 313 return; 314 } 315 316 /* 317 * Count the total number of references for the mounted file system. We 318 * are expecting at least one, which we got when the file system was mounted. 319 * If we find more, it means that 320 * the file system cannot be gracefully unmounted at the moment because 321 * someone is working with it. 322 */ 323 if (vfs_nodes_refcount_sum_get(root->fs_handle, root->service_id) != 1) { 324 fibril_rwlock_write_unlock(&namespace_rwlock); 325 async_answer_0(rid, EBUSY); 326 return; 327 } 328 329 async_exch_t *exch = vfs_exchange_grab(root->fs_handle); 330 rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED, root->service_id); 507 331 vfs_exchange_release(exch); 508 332 509 if (rc != EOK) { 510 fibril_rwlock_write_unlock(&namespace_rwlock); 511 free(mp); 512 vfs_node_put(mr_node); 513 async_answer_0(rid, rc); 514 return; 515 } 516 517 root = NULL; 518 } else { 519 520 /* 521 * Unmounting a non-root file system. 522 * 523 * We have a regular mount point node representing the parent 524 * file system, so we delegate the operation to it. 525 */ 526 527 rc = vfs_lookup_internal(root, mp, L_MP, &mp_res); 528 if (rc != EOK) { 529 fibril_rwlock_write_unlock(&namespace_rwlock); 530 free(mp); 531 vfs_node_put(mr_node); 532 async_answer_0(rid, rc); 533 return; 534 } 535 536 vfs_node_t *mp_node = vfs_node_get(&mp_res); 537 if (!mp_node) { 538 fibril_rwlock_write_unlock(&namespace_rwlock); 539 free(mp); 540 vfs_node_put(mr_node); 541 async_answer_0(rid, ENOMEM); 542 return; 543 } 544 545 exch = vfs_exchange_grab(mp_node->fs_handle); 546 rc = async_req_2_0(exch, VFS_OUT_UNMOUNT, 547 mp_node->service_id, mp_node->index); 548 vfs_exchange_release(exch); 549 550 if (rc != EOK) { 551 fibril_rwlock_write_unlock(&namespace_rwlock); 552 free(mp); 553 vfs_node_put(mp_node); 554 vfs_node_put(mr_node); 555 async_answer_0(rid, rc); 556 return; 557 } 558 559 /* Drop the reference we got above. */ 333 fibril_rwlock_write_unlock(&namespace_rwlock); 334 if (rc == EOK) { 335 vfs_node_forget(root); 336 root = NULL; 337 } 338 async_answer_0(rid, rc); 339 return; 340 } 341 342 /* 343 * Lookup the mounted root and instantiate it. 344 */ 345 vfs_lookup_res_t mp_res; 346 rc = vfs_lookup_internal(root, mp, L_MP, &mp_res); 347 if (rc != EOK) { 348 fibril_rwlock_write_unlock(&namespace_rwlock); 349 free(mp); 350 async_answer_0(rid, rc); 351 return; 352 } 353 vfs_node_t *mp_node = vfs_node_get(&mp_res); 354 if (!mp_node) { 355 fibril_rwlock_write_unlock(&namespace_rwlock); 356 free(mp); 357 async_answer_0(rid, ENOMEM); 358 return; 359 } 360 361 if (mp_node->mount == NULL) { 362 fibril_rwlock_write_unlock(&namespace_rwlock); 560 363 vfs_node_put(mp_node); 561 /* Drop the reference from when the file system was mounted. */ 364 free(mp); 365 async_answer_0(rid, ENOENT); 366 return; 367 } 368 369 /* 370 * Count the total number of references for the mounted file system. We 371 * are expecting at least one, which we got when the file system was mounted. 372 * If we find more, it means that 373 * the file system cannot be gracefully unmounted at the moment because 374 * someone is working with it. 375 */ 376 if (vfs_nodes_refcount_sum_get(mp_node->mount->fs_handle, mp_node->mount->service_id) != 1) { 377 fibril_rwlock_write_unlock(&namespace_rwlock); 562 378 vfs_node_put(mp_node); 563 } 564 565 /* 566 * All went well, the mounted file system was successfully unmounted. 567 * The only thing left is to forget the unmounted root VFS node. 568 */ 569 vfs_node_forget(mr_node); 379 free(mp); 380 async_answer_0(rid, EBUSY); 381 return; 382 } 383 384 /* Unmount the filesystem. */ 385 async_exch_t *exch = vfs_exchange_grab(mp_node->mount->fs_handle); 386 rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED, mp_node->mount->service_id); 387 vfs_exchange_release(exch); 388 389 vfs_node_forget(mp_node->mount); 390 mp_node->mount = NULL; 391 392 vfs_node_put(mp_node); 570 393 fibril_rwlock_write_unlock(&namespace_rwlock); 571 394 572 395 fibril_mutex_lock(&mtab_list_lock); 573 574 396 int found = 0; 575 576 397 list_foreach(mtab_list, cur) { 577 mtab_ent_t *mtab_ent = list_get_instance(cur, mtab_ent_t, 578 link); 398 mtab_ent_t *mtab_ent = list_get_instance(cur, mtab_ent_t, link); 579 399 580 400 if (str_cmp(mtab_ent->mp, mp) == 0) { … … 589 409 fibril_mutex_unlock(&mtab_list_lock); 590 410 591 free(mp); 592 411 free(mp); 412 593 413 async_answer_0(rid, EOK); 414 return; 594 415 } 595 416
Note:
See TracChangeset
for help on using the changeset viewer.