Changeset 368ee04 in mainline for uspace/srv/vfs/vfs_ops.c
- Timestamp:
- 2017-04-05T18:10:39Z (7 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 93ad8166
- Parents:
- 39f892a9 (diff), 2166728 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/vfs/vfs_ops.c
r39f892a9 r368ee04 49 49 #include <unistd.h> 50 50 #include <ctype.h> 51 #include <fcntl.h>52 51 #include <assert.h> 53 52 #include <vfs/canonify.h> 54 #include <vfs/vfs_mtab.h>55 56 FIBRIL_MUTEX_INITIALIZE(mtab_list_lock);57 LIST_INITIALIZE(mtab_list);58 static size_t mtab_size = 0;59 53 60 54 /* Forward declarations of static functions. */ … … 68 62 FIBRIL_RWLOCK_INITIALIZE(namespace_rwlock); 69 63 70 vfs_pair_t rootfs = { 71 .fs_handle = 0, 72 .service_id = 0 73 }; 74 75 static int vfs_mount_internal(ipc_callid_t rid, service_id_t service_id, 76 fs_handle_t fs_handle, char *mp, char *opts) 77 { 78 vfs_lookup_res_t mp_res; 79 vfs_lookup_res_t mr_res; 80 vfs_node_t *mp_node = NULL; 81 vfs_node_t *mr_node; 82 fs_index_t rindex; 83 aoff64_t rsize; 84 unsigned rlnkcnt; 85 async_exch_t *exch; 86 sysarg_t rc; 87 aid_t msg; 64 static size_t shared_path(char *a, char *b) 65 { 66 size_t res = 0; 67 68 while (a[res] == b[res] && a[res] != 0) 69 res++; 70 71 if (a[res] == b[res]) 72 return res; 73 74 res--; 75 while (a[res] != '/') 76 res--; 77 return res; 78 } 79 80 /* This call destroys the file if and only if there are no hard links left. */ 81 static void out_destroy(vfs_triplet_t *file) 82 { 83 async_exch_t *exch = vfs_exchange_grab(file->fs_handle); 84 async_msg_2(exch, VFS_OUT_DESTROY, (sysarg_t) file->service_id, 85 (sysarg_t) file->index); 86 vfs_exchange_release(exch); 87 } 88 89 int vfs_op_clone(int oldfd, int newfd, bool desc) 90 { 91 int rc; 92 93 /* If the file descriptors are the same, do nothing. */ 94 if (oldfd == newfd) 95 return EOK; 96 97 /* Lookup the file structure corresponding to fd. */ 98 vfs_file_t *oldfile = vfs_file_get(oldfd); 99 if (oldfile == NULL) 100 return EBADF; 101 102 assert(oldfile->node != NULL); 103 104 if (newfd != -1) { 105 /* Make sure newfd is closed. */ 106 (void) vfs_fd_free(newfd); 107 /* Assign the old file to newfd. */ 108 rc = vfs_fd_assign(oldfile, newfd); 109 } else { 110 vfs_file_t *newfile; 111 int newfd = vfs_fd_alloc(&newfile, desc); 112 if (newfd >= 0) { 113 newfile->node = oldfile->node; 114 newfile->permissions = oldfile->permissions; 115 vfs_node_addref(newfile->node); 116 117 vfs_file_put(newfile); 118 } 119 rc = newfd; 120 } 121 vfs_file_put(oldfile); 122 123 return rc; 124 } 125 126 int vfs_op_put(int fd) 127 { 128 return vfs_fd_free(fd); 129 } 130 131 static int vfs_connect_internal(service_id_t service_id, unsigned flags, 132 unsigned instance, const char *options, const char *fsname, 133 vfs_node_t **root) 134 { 135 fs_handle_t fs_handle = 0; 136 137 fibril_mutex_lock(&fs_list_lock); 138 while (true) { 139 fs_handle = fs_name_to_handle(instance, fsname, false); 140 141 if (fs_handle != 0 || !(flags & VFS_MOUNT_BLOCKING)) 142 break; 143 144 fibril_condvar_wait(&fs_list_cv, &fs_list_lock); 145 } 146 fibril_mutex_unlock(&fs_list_lock); 147 148 if (fs_handle == 0) 149 return ENOENT; 150 151 /* Tell the mountee that it is being mounted. */ 88 152 ipc_call_t answer; 89 90 /* Resolve the path to the mountpoint. */ 91 fibril_rwlock_write_lock(&namespace_rwlock); 92 if (rootfs.fs_handle) { 93 /* We already have the root FS. */ 94 if (str_cmp(mp, "/") == 0) { 95 /* Trying to mount root FS over root FS */ 96 fibril_rwlock_write_unlock(&namespace_rwlock); 97 async_answer_0(rid, EBUSY); 98 return EBUSY; 99 } 100 101 rc = vfs_lookup_internal(mp, L_MP, &mp_res, NULL); 102 if (rc != EOK) { 103 /* The lookup failed for some reason. */ 104 fibril_rwlock_write_unlock(&namespace_rwlock); 105 async_answer_0(rid, rc); 106 return rc; 107 } 108 109 mp_node = vfs_node_get(&mp_res); 110 if (!mp_node) { 111 fibril_rwlock_write_unlock(&namespace_rwlock); 112 async_answer_0(rid, ENOMEM); 113 return ENOMEM; 114 } 115 116 /* 117 * Now we hold a reference to mp_node. 118 * It will be dropped upon the corresponding VFS_IN_UNMOUNT. 119 * This prevents the mount point from being deleted. 120 */ 121 } else { 122 /* We still don't have the root file system mounted. */ 123 if (str_cmp(mp, "/") == 0) { 124 /* 125 * For this simple, but important case, 126 * we are almost done. 127 */ 128 129 /* Tell the mountee that it is being mounted. */ 130 exch = vfs_exchange_grab(fs_handle); 131 msg = async_send_1(exch, VFS_OUT_MOUNTED, 132 (sysarg_t) service_id, &answer); 133 /* Send the mount options */ 134 rc = async_data_write_start(exch, (void *)opts, 135 str_size(opts)); 136 vfs_exchange_release(exch); 137 138 if (rc != EOK) { 139 async_forget(msg); 140 fibril_rwlock_write_unlock(&namespace_rwlock); 141 async_answer_0(rid, rc); 142 return rc; 143 } 144 async_wait_for(msg, &rc); 145 146 if (rc != EOK) { 147 fibril_rwlock_write_unlock(&namespace_rwlock); 148 async_answer_0(rid, rc); 149 return rc; 150 } 151 152 rindex = (fs_index_t) IPC_GET_ARG1(answer); 153 rsize = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG2(answer), 154 IPC_GET_ARG3(answer)); 155 rlnkcnt = (unsigned) IPC_GET_ARG4(answer); 156 157 mr_res.triplet.fs_handle = fs_handle; 158 mr_res.triplet.service_id = service_id; 159 mr_res.triplet.index = rindex; 160 mr_res.size = rsize; 161 mr_res.lnkcnt = rlnkcnt; 162 mr_res.type = VFS_NODE_DIRECTORY; 163 164 rootfs.fs_handle = fs_handle; 165 rootfs.service_id = service_id; 166 167 /* Add reference to the mounted root. */ 168 mr_node = vfs_node_get(&mr_res); 169 assert(mr_node); 170 171 fibril_rwlock_write_unlock(&namespace_rwlock); 172 async_answer_0(rid, rc); 173 return rc; 174 } else { 175 /* 176 * We can't resolve this without the root filesystem 177 * being mounted first. 178 */ 179 fibril_rwlock_write_unlock(&namespace_rwlock); 180 async_answer_0(rid, ENOENT); 181 return ENOENT; 182 } 183 } 184 185 /* 186 * At this point, we have all necessary pieces: file system handle 187 * and service ID, and we know the mount point VFS node. 188 */ 189 190 async_exch_t *mountee_exch = vfs_exchange_grab(fs_handle); 191 assert(mountee_exch); 192 193 exch = vfs_exchange_grab(mp_res.triplet.fs_handle); 194 msg = async_send_4(exch, VFS_OUT_MOUNT, 195 (sysarg_t) mp_res.triplet.service_id, 196 (sysarg_t) mp_res.triplet.index, 197 (sysarg_t) fs_handle, 198 (sysarg_t) service_id, &answer); 199 200 /* Send connection */ 201 rc = async_exchange_clone(exch, mountee_exch); 202 vfs_exchange_release(mountee_exch); 203 153 async_exch_t *exch = vfs_exchange_grab(fs_handle); 154 aid_t msg = async_send_1(exch, VFS_OUT_MOUNTED, (sysarg_t) service_id, 155 &answer); 156 /* Send the mount options */ 157 sysarg_t rc = async_data_write_start(exch, options, str_size(options)); 158 if (rc != EOK) { 159 async_forget(msg); 160 vfs_exchange_release(exch); 161 return rc; 162 } 163 164 async_wait_for(msg, &rc); 204 165 if (rc != EOK) { 205 166 vfs_exchange_release(exch); 167 return rc; 168 } 169 170 vfs_lookup_res_t res; 171 res.triplet.fs_handle = fs_handle; 172 res.triplet.service_id = service_id; 173 res.triplet.index = (fs_index_t) IPC_GET_ARG1(answer); 174 res.size = (int64_t) MERGE_LOUP32(IPC_GET_ARG2(answer), 175 IPC_GET_ARG3(answer)); 176 res.type = VFS_NODE_DIRECTORY; 177 178 /* Add reference to the mounted root. */ 179 *root = vfs_node_get(&res); 180 if (!*root) { 181 aid_t msg = async_send_1(exch, VFS_OUT_UNMOUNTED, 182 (sysarg_t) service_id, NULL); 206 183 async_forget(msg); 207 208 /* Mount failed, drop reference to mp_node. */ 209 if (mp_node) 210 vfs_node_put(mp_node); 211 212 async_answer_0(rid, rc); 213 fibril_rwlock_write_unlock(&namespace_rwlock); 184 vfs_exchange_release(exch); 185 return ENOMEM; 186 } 187 188 vfs_exchange_release(exch); 189 190 return EOK; 191 } 192 193 int vfs_op_mount(int mpfd, unsigned service_id, unsigned flags, 194 unsigned instance, const char *opts, const char *fs_name, int *outfd) 195 { 196 int rc; 197 vfs_file_t *mp = NULL; 198 vfs_file_t *file = NULL; 199 int fd = -1; 200 201 if (!(flags & VFS_MOUNT_CONNECT_ONLY)) { 202 mp = vfs_file_get(mpfd); 203 if (mp == NULL) { 204 rc = EBADF; 205 goto out; 206 } 207 208 if (mp->node->mount != NULL) { 209 rc = EBUSY; 210 goto out; 211 } 212 213 if (mp->node->type != VFS_NODE_DIRECTORY) { 214 rc = ENOTDIR; 215 goto out; 216 } 217 218 if (vfs_node_has_children(mp->node)) { 219 rc = ENOTEMPTY; 220 goto out; 221 } 222 } 223 224 if (!(flags & VFS_MOUNT_NO_REF)) { 225 fd = vfs_fd_alloc(&file, false); 226 if (fd < 0) { 227 rc = fd; 228 goto out; 229 } 230 } 231 232 vfs_node_t *root = NULL; 233 234 fibril_rwlock_write_lock(&namespace_rwlock); 235 236 rc = vfs_connect_internal(service_id, flags, instance, opts, fs_name, 237 &root); 238 if (rc == EOK && !(flags & VFS_MOUNT_CONNECT_ONLY)) { 239 vfs_node_addref(mp->node); 240 vfs_node_addref(root); 241 mp->node->mount = root; 242 } 243 244 fibril_rwlock_write_unlock(&namespace_rwlock); 245 246 if (rc != EOK) 247 goto out; 248 249 if (flags & VFS_MOUNT_NO_REF) { 250 vfs_node_delref(root); 251 } else { 252 assert(file != NULL); 253 254 file->node = root; 255 file->permissions = MODE_READ | MODE_WRITE | MODE_APPEND; 256 file->open_read = false; 257 file->open_write = false; 258 } 259 260 out: 261 if (mp) 262 vfs_file_put(mp); 263 if (file) 264 vfs_file_put(file); 265 266 if (rc != EOK && fd >= 0) { 267 vfs_fd_free(fd); 268 fd = 0; 269 } 270 271 *outfd = fd; 272 return rc; 273 } 274 275 int vfs_op_open(int fd, int mode) 276 { 277 if (mode == 0) 278 return EINVAL; 279 280 vfs_file_t *file = vfs_file_get(fd); 281 if (!file) 282 return EBADF; 283 284 if ((mode & ~file->permissions) != 0) { 285 vfs_file_put(file); 286 return EPERM; 287 } 288 289 if (file->open_read || file->open_write) { 290 vfs_file_put(file); 291 return EBUSY; 292 } 293 294 file->open_read = (mode & MODE_READ) != 0; 295 file->open_write = (mode & (MODE_WRITE | MODE_APPEND)) != 0; 296 file->append = (mode & MODE_APPEND) != 0; 297 298 if (!file->open_read && !file->open_write) { 299 vfs_file_put(file); 300 return EINVAL; 301 } 302 303 if (file->node->type == VFS_NODE_DIRECTORY && file->open_write) { 304 file->open_read = file->open_write = false; 305 vfs_file_put(file); 306 return EINVAL; 307 } 308 309 int rc = vfs_open_node_remote(file->node); 310 if (rc != EOK) { 311 file->open_read = file->open_write = false; 312 vfs_file_put(file); 214 313 return rc; 215 314 } 216 315 217 /* send the mount options */218 rc = async_data_write_start(exch, (void *) opts, str_size(opts));219 if (rc != EOK) {220 vfs_exchange_release(exch);221 async_forget(msg);222 223 /* Mount failed, drop reference to mp_node. */224 if (mp_node)225 vfs_node_put(mp_node);226 227 fibril_rwlock_write_unlock(&namespace_rwlock);228 async_answer_0(rid, rc);229 return rc;230 }231 232 /*233 * Wait for the answer before releasing the exchange to avoid deadlock234 * in case the answer depends on further calls to the same file system.235 * Think of a case when mounting a FS on a file_bd backed by a file on236 * the same FS.237 */238 async_wait_for(msg, &rc);239 vfs_exchange_release(exch);240 241 if (rc == EOK) {242 rindex = (fs_index_t) IPC_GET_ARG1(answer);243 rsize = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG2(answer),244 IPC_GET_ARG3(answer));245 rlnkcnt = (unsigned) IPC_GET_ARG4(answer);246 247 mr_res.triplet.fs_handle = fs_handle;248 mr_res.triplet.service_id = service_id;249 mr_res.triplet.index = rindex;250 mr_res.size = rsize;251 mr_res.lnkcnt = rlnkcnt;252 mr_res.type = VFS_NODE_DIRECTORY;253 254 /* Add reference to the mounted root. */255 mr_node = vfs_node_get(&mr_res);256 assert(mr_node);257 } else {258 /* Mount failed, drop reference to mp_node. */259 if (mp_node)260 vfs_node_put(mp_node);261 }262 263 async_answer_0(rid, rc);264 fibril_rwlock_write_unlock(&namespace_rwlock);265 return rc;266 }267 268 void vfs_mount_srv(ipc_callid_t rid, ipc_call_t *request)269 {270 service_id_t service_id;271 272 /*273 * We expect the library to do the device-name to device-handle274 * translation for us, thus the device handle will arrive as ARG1275 * in the request.276 */277 service_id = (service_id_t) IPC_GET_ARG1(*request);278 279 /*280 * Mount flags are passed as ARG2.281 */282 unsigned int flags = (unsigned int) IPC_GET_ARG2(*request);283 284 /*285 * Instance number is passed as ARG3.286 */287 unsigned int instance = IPC_GET_ARG3(*request);288 289 /* We want the client to send us the mount point. */290 char *mp;291 int rc = async_data_write_accept((void **) &mp, true, 0, MAX_PATH_LEN,292 0, NULL);293 if (rc != EOK) {294 async_answer_0(rid, rc);295 return;296 }297 298 /* Now we expect to receive the mount options. */299 char *opts;300 rc = async_data_write_accept((void **) &opts, true, 0, MAX_MNTOPTS_LEN,301 0, NULL);302 if (rc != EOK) {303 free(mp);304 async_answer_0(rid, rc);305 return;306 }307 308 /*309 * Now, we expect the client to send us data with the name of the file310 * system.311 */312 char *fs_name;313 rc = async_data_write_accept((void **) &fs_name, true, 0,314 FS_NAME_MAXLEN, 0, NULL);315 if (rc != EOK) {316 free(mp);317 free(opts);318 async_answer_0(rid, rc);319 return;320 }321 322 /*323 * Wait for VFS_IN_PING so that we can return an error if we don't know324 * fs_name.325 */326 ipc_call_t data;327 ipc_callid_t callid = async_get_call(&data);328 if (IPC_GET_IMETHOD(data) != VFS_IN_PING) {329 async_answer_0(callid, ENOTSUP);330 async_answer_0(rid, ENOTSUP);331 free(mp);332 free(opts);333 free(fs_name);334 return;335 }336 337 /*338 * Check if we know a file system with the same name as is in fs_name.339 * This will also give us its file system handle.340 */341 fibril_mutex_lock(&fs_list_lock);342 fs_handle_t fs_handle;343 recheck:344 fs_handle = fs_name_to_handle(instance, fs_name, false);345 if (!fs_handle) {346 if (flags & IPC_FLAG_BLOCKING) {347 fibril_condvar_wait(&fs_list_cv, &fs_list_lock);348 goto recheck;349 }350 351 fibril_mutex_unlock(&fs_list_lock);352 async_answer_0(callid, ENOENT);353 async_answer_0(rid, ENOENT);354 free(mp);355 free(fs_name);356 free(opts);357 return;358 }359 fibril_mutex_unlock(&fs_list_lock);360 361 /* Add the filesystem info to the list of mounted filesystems */362 mtab_ent_t *mtab_ent = malloc(sizeof(mtab_ent_t));363 if (!mtab_ent) {364 async_answer_0(callid, ENOMEM);365 async_answer_0(rid, ENOMEM);366 free(mp);367 free(fs_name);368 free(opts);369 return;370 }371 372 /* Do the mount */373 rc = vfs_mount_internal(rid, service_id, fs_handle, mp, opts);374 if (rc != EOK) {375 async_answer_0(callid, ENOTSUP);376 async_answer_0(rid, ENOTSUP);377 free(mtab_ent);378 free(mp);379 free(opts);380 free(fs_name);381 return;382 }383 384 /* Add the filesystem info to the list of mounted filesystems */385 386 str_cpy(mtab_ent->mp, MAX_PATH_LEN, mp);387 str_cpy(mtab_ent->fs_name, FS_NAME_MAXLEN, fs_name);388 str_cpy(mtab_ent->opts, MAX_MNTOPTS_LEN, opts);389 mtab_ent->instance = instance;390 mtab_ent->service_id = service_id;391 392 link_initialize(&mtab_ent->link);393 394 fibril_mutex_lock(&mtab_list_lock);395 list_append(&mtab_ent->link, &mtab_list);396 mtab_size++;397 fibril_mutex_unlock(&mtab_list_lock);398 399 free(mp);400 free(fs_name);401 free(opts);402 403 /* Acknowledge that we know fs_name. */404 async_answer_0(callid, EOK);405 }406 407 void vfs_unmount_srv(ipc_callid_t rid, ipc_call_t *request)408 {409 int rc;410 char *mp;411 vfs_lookup_res_t mp_res;412 vfs_lookup_res_t mr_res;413 vfs_node_t *mr_node;414 async_exch_t *exch;415 416 /*417 * Receive the mount point path.418 */419 rc = async_data_write_accept((void **) &mp, true, 0, MAX_PATH_LEN,420 0, NULL);421 if (rc != EOK)422 async_answer_0(rid, rc);423 424 /*425 * Taking the namespace lock will do two things for us. First, it will426 * prevent races with other lookup operations. Second, it will stop new427 * references to already existing VFS nodes and creation of new VFS428 * nodes. This is because new references are added as a result of some429 * lookup operation or at least of some operation which is protected by430 * the namespace lock.431 */432 fibril_rwlock_write_lock(&namespace_rwlock);433 434 /*435 * Lookup the mounted root and instantiate it.436 */437 rc = vfs_lookup_internal(mp, L_ROOT, &mr_res, NULL);438 if (rc != EOK) {439 fibril_rwlock_write_unlock(&namespace_rwlock);440 free(mp);441 async_answer_0(rid, rc);442 return;443 }444 mr_node = vfs_node_get(&mr_res);445 if (!mr_node) {446 fibril_rwlock_write_unlock(&namespace_rwlock);447 free(mp);448 async_answer_0(rid, ENOMEM);449 return;450 }451 452 /*453 * Count the total number of references for the mounted file system. We454 * are expecting at least two. One which we got above and one which we455 * got when the file system was mounted. If we find more, it means that456 * the file system cannot be gracefully unmounted at the moment because457 * someone is working with it.458 */459 if (vfs_nodes_refcount_sum_get(mr_node->fs_handle,460 mr_node->service_id) != 2) {461 fibril_rwlock_write_unlock(&namespace_rwlock);462 vfs_node_put(mr_node);463 free(mp);464 async_answer_0(rid, EBUSY);465 return;466 }467 468 if (str_cmp(mp, "/") == 0) {469 470 /*471 * Unmounting the root file system.472 *473 * In this case, there is no mount point node and we send474 * VFS_OUT_UNMOUNTED directly to the mounted file system.475 */476 477 exch = vfs_exchange_grab(mr_node->fs_handle);478 rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED,479 mr_node->service_id);480 vfs_exchange_release(exch);481 482 if (rc != EOK) {483 fibril_rwlock_write_unlock(&namespace_rwlock);484 free(mp);485 vfs_node_put(mr_node);486 async_answer_0(rid, rc);487 return;488 }489 490 rootfs.fs_handle = 0;491 rootfs.service_id = 0;492 } else {493 494 /*495 * Unmounting a non-root file system.496 *497 * We have a regular mount point node representing the parent498 * file system, so we delegate the operation to it.499 */500 501 rc = vfs_lookup_internal(mp, L_MP, &mp_res, NULL);502 if (rc != EOK) {503 fibril_rwlock_write_unlock(&namespace_rwlock);504 free(mp);505 vfs_node_put(mr_node);506 async_answer_0(rid, rc);507 return;508 }509 510 vfs_node_t *mp_node = vfs_node_get(&mp_res);511 if (!mp_node) {512 fibril_rwlock_write_unlock(&namespace_rwlock);513 free(mp);514 vfs_node_put(mr_node);515 async_answer_0(rid, ENOMEM);516 return;517 }518 519 exch = vfs_exchange_grab(mp_node->fs_handle);520 rc = async_req_2_0(exch, VFS_OUT_UNMOUNT,521 mp_node->service_id, mp_node->index);522 vfs_exchange_release(exch);523 524 if (rc != EOK) {525 fibril_rwlock_write_unlock(&namespace_rwlock);526 free(mp);527 vfs_node_put(mp_node);528 vfs_node_put(mr_node);529 async_answer_0(rid, rc);530 return;531 }532 533 /* Drop the reference we got above. */534 vfs_node_put(mp_node);535 /* Drop the reference from when the file system was mounted. */536 vfs_node_put(mp_node);537 }538 539 /*540 * All went well, the mounted file system was successfully unmounted.541 * The only thing left is to forget the unmounted root VFS node.542 */543 vfs_node_forget(mr_node);544 fibril_rwlock_write_unlock(&namespace_rwlock);545 546 fibril_mutex_lock(&mtab_list_lock);547 548 int found = 0;549 550 list_foreach(mtab_list, link, mtab_ent_t, mtab_ent) {551 if (str_cmp(mtab_ent->mp, mp) == 0) {552 list_remove(&mtab_ent->link);553 mtab_size--;554 free(mtab_ent);555 found = 1;556 break;557 }558 }559 assert(found);560 fibril_mutex_unlock(&mtab_list_lock);561 562 free(mp);563 564 async_answer_0(rid, EOK);565 }566 567 void vfs_open(ipc_callid_t rid, ipc_call_t *request)568 {569 /*570 * The POSIX interface is open(path, oflag, mode).571 * We can receive oflags and mode along with the VFS_IN_OPEN call;572 * the path will need to arrive in another call.573 *574 * We also receive one private, non-POSIX set of flags called lflag575 * used to pass information to vfs_lookup_internal().576 */577 int lflag = IPC_GET_ARG1(*request);578 int oflag = IPC_GET_ARG2(*request);579 int mode = IPC_GET_ARG3(*request);580 581 /* Ignore mode for now. */582 (void) mode;583 584 /*585 * Make sure that we are called with exactly one of L_FILE and586 * L_DIRECTORY. Make sure that the user does not pass L_OPEN,587 * L_ROOT or L_MP.588 */589 if (((lflag & (L_FILE | L_DIRECTORY)) == 0) ||590 ((lflag & (L_FILE | L_DIRECTORY)) == (L_FILE | L_DIRECTORY)) ||591 (lflag & (L_OPEN | L_ROOT | L_MP))) {592 async_answer_0(rid, EINVAL);593 return;594 }595 596 if (oflag & O_CREAT)597 lflag |= L_CREATE;598 if (oflag & O_EXCL)599 lflag |= L_EXCLUSIVE;600 601 char *path;602 int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);603 if (rc != EOK) {604 async_answer_0(rid, rc);605 return;606 }607 608 /*609 * Avoid the race condition in which the file can be deleted before we610 * find/create-and-lock the VFS node corresponding to the looked-up611 * triplet.612 */613 if (lflag & L_CREATE)614 fibril_rwlock_write_lock(&namespace_rwlock);615 else616 fibril_rwlock_read_lock(&namespace_rwlock);617 618 /* The path is now populated and we can call vfs_lookup_internal(). */619 vfs_lookup_res_t lr;620 rc = vfs_lookup_internal(path, lflag | L_OPEN, &lr, NULL);621 if (rc != EOK) {622 if (lflag & L_CREATE)623 fibril_rwlock_write_unlock(&namespace_rwlock);624 else625 fibril_rwlock_read_unlock(&namespace_rwlock);626 async_answer_0(rid, rc);627 free(path);628 return;629 }630 631 /* Path is no longer needed. */632 free(path);633 634 vfs_node_t *node = vfs_node_get(&lr);635 if (lflag & L_CREATE)636 fibril_rwlock_write_unlock(&namespace_rwlock);637 else638 fibril_rwlock_read_unlock(&namespace_rwlock);639 640 if (!node) {641 async_answer_0(rid, ENOMEM);642 return;643 }644 645 /* Truncate the file if requested and if necessary. */646 if (oflag & O_TRUNC) {647 fibril_rwlock_write_lock(&node->contents_rwlock);648 if (node->size) {649 rc = vfs_truncate_internal(node->fs_handle,650 node->service_id, node->index, 0);651 if (rc) {652 fibril_rwlock_write_unlock(&node->contents_rwlock);653 vfs_node_put(node);654 async_answer_0(rid, rc);655 return;656 }657 node->size = 0;658 }659 fibril_rwlock_write_unlock(&node->contents_rwlock);660 }661 662 /*663 * Get ourselves a file descriptor and the corresponding vfs_file_t664 * structure.665 */666 int fd = vfs_fd_alloc((oflag & O_DESC) != 0);667 if (fd < 0) {668 vfs_node_put(node);669 async_answer_0(rid, fd);670 return;671 }672 vfs_file_t *file = vfs_file_get(fd);673 assert(file);674 file->node = node;675 if (oflag & O_APPEND)676 file->append = true;677 678 /*679 * The following increase in reference count is for the fact that the680 * file is being opened and that a file structure is pointing to it.681 * It is necessary so that the file will not disappear when682 * vfs_node_put() is called. The reference will be dropped by the683 * respective VFS_IN_CLOSE.684 */685 vfs_node_addref(node);686 vfs_node_put(node);687 316 vfs_file_put(file); 688 689 /* Success! Return the new file descriptor to the client. */ 690 async_answer_1(rid, EOK, fd); 691 } 692 693 void vfs_sync(ipc_callid_t rid, ipc_call_t *request) 694 { 695 int fd = IPC_GET_ARG1(*request); 696 697 /* Lookup the file structure corresponding to the file descriptor. */ 698 vfs_file_t *file = vfs_file_get(fd); 699 if (!file) { 700 async_answer_0(rid, ENOENT); 701 return; 702 } 703 704 /* 705 * Lock the open file structure so that no other thread can manipulate 706 * the same open file at a time. 707 */ 708 fibril_mutex_lock(&file->lock); 709 async_exch_t *fs_exch = vfs_exchange_grab(file->node->fs_handle); 710 711 /* Make a VFS_OUT_SYMC request at the destination FS server. */ 712 aid_t msg; 713 ipc_call_t answer; 714 msg = async_send_2(fs_exch, VFS_OUT_SYNC, file->node->service_id, 715 file->node->index, &answer); 716 717 vfs_exchange_release(fs_exch); 718 719 /* Wait for reply from the FS server. */ 720 sysarg_t rc; 721 async_wait_for(msg, &rc); 722 723 fibril_mutex_unlock(&file->lock); 724 725 vfs_file_put(file); 726 async_answer_0(rid, rc); 727 } 728 729 void vfs_close(ipc_callid_t rid, ipc_call_t *request) 730 { 731 int fd = IPC_GET_ARG1(*request); 732 int ret = vfs_fd_free(fd); 733 async_answer_0(rid, ret); 734 } 735 736 typedef int (* rdwr_ipc_cb_t)(async_exch_t *, vfs_file_t *, ipc_call_t *, 737 bool, void *); 738 739 static int rdwr_ipc_client(async_exch_t *exch, vfs_file_t *file, 317 return EOK; 318 } 319 320 typedef int (* rdwr_ipc_cb_t)(async_exch_t *, vfs_file_t *, aoff64_t, 321 ipc_call_t *, bool, void *); 322 323 static int rdwr_ipc_client(async_exch_t *exch, vfs_file_t *file, aoff64_t pos, 740 324 ipc_call_t *answer, bool read, void *data) 741 325 { … … 754 338 rc = async_data_read_forward_4_1(exch, VFS_OUT_READ, 755 339 file->node->service_id, file->node->index, 756 LOWER32( file->pos), UPPER32(file->pos), answer);340 LOWER32(pos), UPPER32(pos), answer); 757 341 } else { 758 342 rc = async_data_write_forward_4_1(exch, VFS_OUT_WRITE, 759 343 file->node->service_id, file->node->index, 760 LOWER32( file->pos), UPPER32(file->pos), answer);344 LOWER32(pos), UPPER32(pos), answer); 761 345 } 762 346 … … 765 349 } 766 350 767 static int rdwr_ipc_internal(async_exch_t *exch, vfs_file_t *file, 351 static int rdwr_ipc_internal(async_exch_t *exch, vfs_file_t *file, aoff64_t pos, 768 352 ipc_call_t *answer, bool read, void *data) 769 353 { … … 774 358 775 359 aid_t msg = async_send_fast(exch, read ? VFS_OUT_READ : VFS_OUT_WRITE, 776 file->node->service_id, file->node->index, LOWER32( file->pos),777 UPPER32( file->pos), answer);360 file->node->service_id, file->node->index, LOWER32(pos), 361 UPPER32(pos), answer); 778 362 if (msg == 0) 779 363 return EINVAL; … … 793 377 } 794 378 795 static int vfs_rdwr(int fd, bool read, rdwr_ipc_cb_t ipc_cb, void *ipc_cb_data) 379 static int vfs_rdwr(int fd, aoff64_t pos, bool read, rdwr_ipc_cb_t ipc_cb, 380 void *ipc_cb_data) 796 381 { 797 382 /* … … 808 393 vfs_file_t *file = vfs_file_get(fd); 809 394 if (!file) 810 return ENOENT; 811 812 /* 813 * Lock the open file structure so that no other thread can manipulate 814 * the same open file at a time. 815 */ 816 fibril_mutex_lock(&file->lock); 395 return EBADF; 396 397 if ((read && !file->open_read) || (!read && !file->open_write)) { 398 vfs_file_put(file); 399 return EINVAL; 400 } 817 401 818 402 vfs_info_t *fs_info = fs_handle_to_info(file->node->fs_handle); 819 403 assert(fs_info); 404 405 bool rlock = read || 406 (fs_info->concurrent_read_write && fs_info->write_retains_size); 820 407 821 408 /* … … 824 411 * write implementation does not modify the file size. 825 412 */ 826 if ((read) || 827 ((fs_info->concurrent_read_write) && (fs_info->write_retains_size))) 413 if (rlock) 828 414 fibril_rwlock_read_lock(&file->node->contents_rwlock); 829 415 else … … 835 421 * while we are in readdir(). 836 422 */ 837 assert(read); 423 424 if (!read) { 425 if (rlock) { 426 fibril_rwlock_read_unlock( 427 &file->node->contents_rwlock); 428 } else { 429 fibril_rwlock_write_unlock( 430 &file->node->contents_rwlock); 431 } 432 vfs_file_put(file); 433 return EINVAL; 434 } 435 838 436 fibril_rwlock_read_lock(&namespace_rwlock); 839 437 } … … 842 440 843 441 if (!read && file->append) 844 file->pos = file->node->size;442 pos = file->node->size; 845 443 846 444 /* … … 848 446 */ 849 447 ipc_call_t answer; 850 int rc = ipc_cb(fs_exch, file, &answer, read, ipc_cb_data);448 int rc = ipc_cb(fs_exch, file, pos, &answer, read, ipc_cb_data); 851 449 852 450 vfs_exchange_release(fs_exch); 853 854 size_t bytes = IPC_GET_ARG1(answer);855 451 856 452 if (file->node->type == VFS_NODE_DIRECTORY) … … 858 454 859 455 /* Unlock the VFS node. */ 860 if ((read) || 861 ((fs_info->concurrent_read_write) && (fs_info->write_retains_size))) 456 if (rlock) { 862 457 fibril_rwlock_read_unlock(&file->node->contents_rwlock); 863 else {458 } else { 864 459 /* Update the cached version of node's size. */ 865 if (rc == EOK) 460 if (rc == EOK) { 866 461 file->node->size = MERGE_LOUP32(IPC_GET_ARG2(answer), 867 462 IPC_GET_ARG3(answer)); 463 } 868 464 fibril_rwlock_write_unlock(&file->node->contents_rwlock); 869 465 } 870 466 871 /* Update the position pointer and unlock the open file. */ 467 vfs_file_put(file); 468 469 return rc; 470 } 471 472 int vfs_rdwr_internal(int fd, aoff64_t pos, bool read, rdwr_io_chunk_t *chunk) 473 { 474 return vfs_rdwr(fd, pos, read, rdwr_ipc_internal, chunk); 475 } 476 477 int vfs_op_read(int fd, aoff64_t pos, size_t *out_bytes) 478 { 479 return vfs_rdwr(fd, pos, true, rdwr_ipc_client, out_bytes); 480 } 481 482 int vfs_op_rename(int basefd, char *old, char *new) 483 { 484 vfs_file_t *base_file = vfs_file_get(basefd); 485 if (!base_file) 486 return EBADF; 487 488 vfs_node_t *base = base_file->node; 489 vfs_node_addref(base); 490 vfs_file_put(base_file); 491 492 vfs_lookup_res_t base_lr; 493 vfs_lookup_res_t old_lr; 494 vfs_lookup_res_t new_lr_orig; 495 bool orig_unlinked = false; 496 497 int rc; 498 499 size_t shared = shared_path(old, new); 500 501 /* Do not allow one path to be a prefix of the other. */ 502 if (old[shared] == 0 || new[shared] == 0) { 503 vfs_node_put(base); 504 return EINVAL; 505 } 506 assert(old[shared] == '/'); 507 assert(new[shared] == '/'); 508 509 fibril_rwlock_write_lock(&namespace_rwlock); 510 511 /* Resolve the shared portion of the path first. */ 512 if (shared != 0) { 513 old[shared] = 0; 514 rc = vfs_lookup_internal(base, old, L_DIRECTORY, &base_lr); 515 if (rc != EOK) { 516 vfs_node_put(base); 517 fibril_rwlock_write_unlock(&namespace_rwlock); 518 return rc; 519 } 520 521 vfs_node_put(base); 522 base = vfs_node_get(&base_lr); 523 if (!base) { 524 fibril_rwlock_write_unlock(&namespace_rwlock); 525 return ENOMEM; 526 } 527 old[shared] = '/'; 528 old += shared; 529 new += shared; 530 } 531 532 rc = vfs_lookup_internal(base, old, L_DISABLE_MOUNTS, &old_lr); 533 if (rc != EOK) { 534 vfs_node_put(base); 535 fibril_rwlock_write_unlock(&namespace_rwlock); 536 return rc; 537 } 538 539 rc = vfs_lookup_internal(base, new, L_UNLINK | L_DISABLE_MOUNTS, 540 &new_lr_orig); 541 if (rc == EOK) { 542 orig_unlinked = true; 543 } else if (rc != ENOENT) { 544 vfs_node_put(base); 545 fibril_rwlock_write_unlock(&namespace_rwlock); 546 return rc; 547 } 548 549 rc = vfs_link_internal(base, new, &old_lr.triplet); 550 if (rc != EOK) { 551 vfs_link_internal(base, old, &old_lr.triplet); 552 if (orig_unlinked) 553 vfs_link_internal(base, new, &new_lr_orig.triplet); 554 vfs_node_put(base); 555 fibril_rwlock_write_unlock(&namespace_rwlock); 556 return rc; 557 } 558 559 rc = vfs_lookup_internal(base, old, L_UNLINK | L_DISABLE_MOUNTS, 560 &old_lr); 561 if (rc != EOK) { 562 if (orig_unlinked) 563 vfs_link_internal(base, new, &new_lr_orig.triplet); 564 vfs_node_put(base); 565 fibril_rwlock_write_unlock(&namespace_rwlock); 566 return rc; 567 } 568 569 /* If the node is not held by anyone, try to destroy it. */ 570 if (orig_unlinked) { 571 vfs_node_t *node = vfs_node_peek(&new_lr_orig); 572 if (!node) 573 out_destroy(&new_lr_orig.triplet); 574 else 575 vfs_node_put(node); 576 } 577 578 vfs_node_put(base); 579 fibril_rwlock_write_unlock(&namespace_rwlock); 580 return EOK; 581 } 582 583 int vfs_op_resize(int fd, int64_t size) 584 { 585 vfs_file_t *file = vfs_file_get(fd); 586 if (!file) 587 return EBADF; 588 589 fibril_rwlock_write_lock(&file->node->contents_rwlock); 590 591 int rc = vfs_truncate_internal(file->node->fs_handle, 592 file->node->service_id, file->node->index, size); 872 593 if (rc == EOK) 873 file-> pos += bytes;874 fibril_mutex_unlock(&file->lock);875 vfs_file_put(file);876 594 file->node->size = size; 595 596 fibril_rwlock_write_unlock(&file->node->contents_rwlock); 597 vfs_file_put(file); 877 598 return rc; 878 599 } 879 880 static void vfs_rdwr_client(ipc_callid_t rid, ipc_call_t *request, bool read) 881 { 882 size_t bytes = 0; 883 int rc = vfs_rdwr(IPC_GET_ARG1(*request), read, rdwr_ipc_client, 884 &bytes); 885 async_answer_1(rid, rc, bytes); 886 } 887 888 int vfs_rdwr_internal(int fd, bool read, rdwr_io_chunk_t *chunk) 889 { 890 return vfs_rdwr(fd, read, rdwr_ipc_internal, chunk); 891 } 892 893 void vfs_read(ipc_callid_t rid, ipc_call_t *request) 894 { 895 vfs_rdwr_client(rid, request, true); 896 } 897 898 void vfs_write(ipc_callid_t rid, ipc_call_t *request) 899 { 900 vfs_rdwr_client(rid, request, false); 901 } 902 903 void vfs_seek(ipc_callid_t rid, ipc_call_t *request) 904 { 905 int fd = (int) IPC_GET_ARG1(*request); 906 off64_t off = (off64_t) MERGE_LOUP32(IPC_GET_ARG2(*request), 907 IPC_GET_ARG3(*request)); 908 int whence = (int) IPC_GET_ARG4(*request); 909 910 /* Lookup the file structure corresponding to the file descriptor. */ 600 601 int vfs_op_stat(int fd) 602 { 911 603 vfs_file_t *file = vfs_file_get(fd); 912 if (!file) { 913 async_answer_0(rid, ENOENT); 914 return; 915 } 916 917 fibril_mutex_lock(&file->lock); 918 919 off64_t newoff; 920 switch (whence) { 921 case SEEK_SET: 922 if (off >= 0) { 923 file->pos = (aoff64_t) off; 924 fibril_mutex_unlock(&file->lock); 925 vfs_file_put(file); 926 async_answer_1(rid, EOK, off); 927 return; 928 } 929 break; 930 case SEEK_CUR: 931 if ((off >= 0) && (file->pos + off < file->pos)) { 932 fibril_mutex_unlock(&file->lock); 933 vfs_file_put(file); 934 async_answer_0(rid, EOVERFLOW); 935 return; 936 } 937 938 if ((off < 0) && (file->pos < (aoff64_t) -off)) { 939 fibril_mutex_unlock(&file->lock); 940 vfs_file_put(file); 941 async_answer_0(rid, EOVERFLOW); 942 return; 943 } 944 945 file->pos += off; 946 newoff = (file->pos > OFF64_MAX) ? OFF64_MAX : file->pos; 947 948 fibril_mutex_unlock(&file->lock); 949 vfs_file_put(file); 950 async_answer_2(rid, EOK, LOWER32(newoff), 951 UPPER32(newoff)); 952 return; 953 case SEEK_END: 954 fibril_rwlock_read_lock(&file->node->contents_rwlock); 955 aoff64_t size = file->node->size; 956 957 if ((off >= 0) && (size + off < size)) { 958 fibril_rwlock_read_unlock(&file->node->contents_rwlock); 959 fibril_mutex_unlock(&file->lock); 960 vfs_file_put(file); 961 async_answer_0(rid, EOVERFLOW); 962 return; 963 } 964 965 if ((off < 0) && (size < (aoff64_t) -off)) { 966 fibril_rwlock_read_unlock(&file->node->contents_rwlock); 967 fibril_mutex_unlock(&file->lock); 968 vfs_file_put(file); 969 async_answer_0(rid, EOVERFLOW); 970 return; 971 } 972 973 file->pos = size + off; 974 newoff = (file->pos > OFF64_MAX) ? OFF64_MAX : file->pos; 975 976 fibril_rwlock_read_unlock(&file->node->contents_rwlock); 977 fibril_mutex_unlock(&file->lock); 978 vfs_file_put(file); 979 async_answer_2(rid, EOK, LOWER32(newoff), UPPER32(newoff)); 980 return; 981 } 982 983 fibril_mutex_unlock(&file->lock); 604 if (!file) 605 return EBADF; 606 607 vfs_node_t *node = file->node; 608 609 async_exch_t *exch = vfs_exchange_grab(node->fs_handle); 610 int rc = async_data_read_forward_fast(exch, VFS_OUT_STAT, 611 node->service_id, node->index, true, 0, NULL); 612 vfs_exchange_release(exch); 613 984 614 vfs_file_put(file); 985 async_answer_0(rid, EINVAL); 986 } 987 988 int vfs_truncate_internal(fs_handle_t fs_handle, service_id_t service_id, 615 return rc; 616 } 617 618 int vfs_op_statfs(int fd) 619 { 620 vfs_file_t *file = vfs_file_get(fd); 621 if (!file) 622 return EBADF; 623 624 vfs_node_t *node = file->node; 625 626 async_exch_t *exch = vfs_exchange_grab(node->fs_handle); 627 int rc = async_data_read_forward_fast(exch, VFS_OUT_STATFS, 628 node->service_id, node->index, false, 0, NULL); 629 vfs_exchange_release(exch); 630 631 vfs_file_put(file); 632 return rc; 633 } 634 635 int vfs_op_sync(int fd) 636 { 637 vfs_file_t *file = vfs_file_get(fd); 638 if (!file) 639 return EBADF; 640 641 async_exch_t *fs_exch = vfs_exchange_grab(file->node->fs_handle); 642 643 aid_t msg; 644 ipc_call_t answer; 645 msg = async_send_2(fs_exch, VFS_OUT_SYNC, file->node->service_id, 646 file->node->index, &answer); 647 648 vfs_exchange_release(fs_exch); 649 650 sysarg_t rc; 651 async_wait_for(msg, &rc); 652 653 vfs_file_put(file); 654 return rc; 655 656 } 657 658 static int vfs_truncate_internal(fs_handle_t fs_handle, service_id_t service_id, 989 659 fs_index_t index, aoff64_t size) 990 660 { … … 998 668 } 999 669 1000 void vfs_truncate(ipc_callid_t rid, ipc_call_t *request) 1001 { 1002 int fd = IPC_GET_ARG1(*request); 1003 aoff64_t size = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG2(*request), 1004 IPC_GET_ARG3(*request)); 1005 int rc; 1006 1007 vfs_file_t *file = vfs_file_get(fd); 1008 if (!file) { 1009 async_answer_0(rid, ENOENT); 1010 return; 1011 } 1012 fibril_mutex_lock(&file->lock); 1013 1014 fibril_rwlock_write_lock(&file->node->contents_rwlock); 1015 rc = vfs_truncate_internal(file->node->fs_handle, 1016 file->node->service_id, file->node->index, size); 1017 if (rc == EOK) 1018 file->node->size = size; 1019 fibril_rwlock_write_unlock(&file->node->contents_rwlock); 1020 1021 fibril_mutex_unlock(&file->lock); 1022 vfs_file_put(file); 1023 async_answer_0(rid, (sysarg_t)rc); 1024 } 1025 1026 void vfs_fstat(ipc_callid_t rid, ipc_call_t *request) 1027 { 1028 int fd = IPC_GET_ARG1(*request); 1029 sysarg_t rc; 1030 1031 vfs_file_t *file = vfs_file_get(fd); 1032 if (!file) { 1033 async_answer_0(rid, ENOENT); 1034 return; 1035 } 1036 1037 ipc_callid_t callid; 1038 if (!async_data_read_receive(&callid, NULL)) { 1039 vfs_file_put(file); 1040 async_answer_0(callid, EINVAL); 1041 async_answer_0(rid, EINVAL); 1042 return; 1043 } 1044 1045 fibril_mutex_lock(&file->lock); 1046 1047 async_exch_t *exch = vfs_exchange_grab(file->node->fs_handle); 1048 1049 aid_t msg; 1050 msg = async_send_3(exch, VFS_OUT_STAT, file->node->service_id, 1051 file->node->index, true, NULL); 1052 async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME); 1053 670 int vfs_op_unlink(int parentfd, int expectfd, char *path) 671 { 672 int rc = EOK; 673 vfs_file_t *parent = NULL; 674 vfs_file_t *expect = NULL; 675 676 if (parentfd == expectfd) 677 return EINVAL; 678 679 fibril_rwlock_write_lock(&namespace_rwlock); 680 681 /* 682 * Files are retrieved in order of file descriptors, to prevent 683 * deadlock. 684 */ 685 if (parentfd < expectfd) { 686 parent = vfs_file_get(parentfd); 687 if (!parent) { 688 rc = EBADF; 689 goto exit; 690 } 691 } 692 693 if (expectfd >= 0) { 694 expect = vfs_file_get(expectfd); 695 if (!expect) { 696 rc = EBADF; 697 goto exit; 698 } 699 } 700 701 if (parentfd > expectfd) { 702 parent = vfs_file_get(parentfd); 703 if (!parent) { 704 rc = EBADF; 705 goto exit; 706 } 707 } 708 709 assert(parent != NULL); 710 711 if (expectfd >= 0) { 712 vfs_lookup_res_t lr; 713 rc = vfs_lookup_internal(parent->node, path, 0, &lr); 714 if (rc != EOK) 715 goto exit; 716 717 vfs_node_t *found_node = vfs_node_peek(&lr); 718 vfs_node_put(found_node); 719 if (expect->node != found_node) { 720 rc = ENOENT; 721 goto exit; 722 } 723 724 vfs_file_put(expect); 725 expect = NULL; 726 } 727 728 vfs_lookup_res_t lr; 729 rc = vfs_lookup_internal(parent->node, path, L_UNLINK, &lr); 730 if (rc != EOK) 731 goto exit; 732 733 /* If the node is not held by anyone, try to destroy it. */ 734 vfs_node_t *node = vfs_node_peek(&lr); 735 if (!node) 736 out_destroy(&lr.triplet); 737 else 738 vfs_node_put(node); 739 740 exit: 741 if (path) 742 free(path); 743 if (parent) 744 vfs_file_put(parent); 745 if (expect) 746 vfs_file_put(expect); 747 fibril_rwlock_write_unlock(&namespace_rwlock); 748 return rc; 749 } 750 751 int vfs_op_unmount(int mpfd) 752 { 753 vfs_file_t *mp = vfs_file_get(mpfd); 754 if (mp == NULL) 755 return EBADF; 756 757 if (mp->node->mount == NULL) { 758 vfs_file_put(mp); 759 return ENOENT; 760 } 761 762 fibril_rwlock_write_lock(&namespace_rwlock); 763 764 /* 765 * Count the total number of references for the mounted file system. We 766 * are expecting at least one, which is held by the mount point. 767 * If we find more, it means that 768 * the file system cannot be gracefully unmounted at the moment because 769 * someone is working with it. 770 */ 771 if (vfs_nodes_refcount_sum_get(mp->node->mount->fs_handle, 772 mp->node->mount->service_id) != 1) { 773 vfs_file_put(mp); 774 fibril_rwlock_write_unlock(&namespace_rwlock); 775 return EBUSY; 776 } 777 778 async_exch_t *exch = vfs_exchange_grab(mp->node->mount->fs_handle); 779 int rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED, 780 mp->node->mount->service_id); 1054 781 vfs_exchange_release(exch); 1055 782 1056 async_wait_for(msg, &rc);1057 1058 fibril_mutex_unlock(&file->lock);1059 vfs_file_put(file);1060 async_answer_0(rid, rc);1061 }1062 1063 void vfs_stat(ipc_callid_t rid, ipc_call_t *request)1064 {1065 char *path;1066 int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);1067 783 if (rc != EOK) { 1068 async_answer_0(rid, rc); 1069 return; 1070 } 1071 1072 ipc_callid_t callid; 1073 if (!async_data_read_receive(&callid, NULL)) { 1074 free(path); 1075 async_answer_0(callid, EINVAL); 1076 async_answer_0(rid, EINVAL); 1077 return; 1078 } 1079 784 vfs_file_put(mp); 785 fibril_rwlock_write_unlock(&namespace_rwlock); 786 return rc; 787 } 788 789 vfs_node_forget(mp->node->mount); 790 vfs_node_put(mp->node); 791 mp->node->mount = NULL; 792 793 fibril_rwlock_write_unlock(&namespace_rwlock); 794 795 vfs_file_put(mp); 796 return EOK; 797 } 798 799 int vfs_op_wait_handle(bool high_fd) 800 { 801 return vfs_wait_handle_internal(high_fd); 802 } 803 804 static inline bool walk_flags_valid(int flags) 805 { 806 if ((flags & ~WALK_ALL_FLAGS) != 0) 807 return false; 808 if ((flags & WALK_MAY_CREATE) && (flags & WALK_MUST_CREATE)) 809 return false; 810 if ((flags & WALK_REGULAR) && (flags & WALK_DIRECTORY)) 811 return false; 812 if ((flags & WALK_MAY_CREATE) || (flags & WALK_MUST_CREATE)) { 813 if (!(flags & WALK_DIRECTORY) && !(flags & WALK_REGULAR)) 814 return false; 815 } 816 return true; 817 } 818 819 static inline int walk_lookup_flags(int flags) 820 { 821 int lflags = 0; 822 if ((flags & WALK_MAY_CREATE) || (flags & WALK_MUST_CREATE)) 823 lflags |= L_CREATE; 824 if (flags & WALK_MUST_CREATE) 825 lflags |= L_EXCLUSIVE; 826 if (flags & WALK_REGULAR) 827 lflags |= L_FILE; 828 if (flags & WALK_DIRECTORY) 829 lflags |= L_DIRECTORY; 830 if (flags & WALK_MOUNT_POINT) 831 lflags |= L_MP; 832 return lflags; 833 } 834 835 int vfs_op_walk(int parentfd, int flags, char *path, int *out_fd) 836 { 837 if (!walk_flags_valid(flags)) 838 return EINVAL; 839 840 vfs_file_t *parent = vfs_file_get(parentfd); 841 if (!parent) 842 return EBADF; 843 844 fibril_rwlock_read_lock(&namespace_rwlock); 845 1080 846 vfs_lookup_res_t lr; 1081 fibril_rwlock_read_lock(&namespace_rwlock); 1082 rc = vfs_lookup_internal(path, L_NONE, &lr, NULL); 1083 free(path); 847 int rc = vfs_lookup_internal(parent->node, path, 848 walk_lookup_flags(flags), &lr); 1084 849 if (rc != EOK) { 1085 850 fibril_rwlock_read_unlock(&namespace_rwlock); 1086 async_answer_0(callid, rc);1087 async_answer_0(rid, rc);1088 return;1089 }851 vfs_file_put(parent); 852 return rc; 853 } 854 1090 855 vfs_node_t *node = vfs_node_get(&lr); 1091 856 if (!node) { 1092 857 fibril_rwlock_read_unlock(&namespace_rwlock); 1093 async_answer_0(callid, ENOMEM); 1094 async_answer_0(rid, ENOMEM); 1095 return; 1096 } 1097 858 vfs_file_put(parent); 859 return ENOMEM; 860 } 861 862 vfs_file_t *file; 863 int fd = vfs_fd_alloc(&file, false); 864 if (fd < 0) { 865 vfs_node_put(node); 866 vfs_file_put(parent); 867 return fd; 868 } 869 assert(file != NULL); 870 871 file->node = node; 872 file->permissions = parent->permissions; 873 file->open_read = false; 874 file->open_write = false; 875 876 vfs_file_put(file); 877 vfs_file_put(parent); 878 1098 879 fibril_rwlock_read_unlock(&namespace_rwlock); 1099 880 1100 async_exch_t *exch = vfs_exchange_grab(node->fs_handle); 1101 1102 aid_t msg; 1103 msg = async_send_3(exch, VFS_OUT_STAT, node->service_id, 1104 node->index, false, NULL); 1105 async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME); 1106 1107 vfs_exchange_release(exch); 1108 1109 sysarg_t rv; 1110 async_wait_for(msg, &rv); 1111 1112 async_answer_0(rid, rv); 1113 1114 vfs_node_put(node); 1115 } 1116 1117 void vfs_mkdir(ipc_callid_t rid, ipc_call_t *request) 1118 { 1119 int mode = IPC_GET_ARG1(*request); 1120 1121 char *path; 1122 int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL); 1123 if (rc != EOK) { 1124 async_answer_0(rid, rc); 1125 return; 1126 } 1127 1128 /* Ignore mode for now. */ 1129 (void) mode; 1130 1131 fibril_rwlock_write_lock(&namespace_rwlock); 1132 int lflag = L_DIRECTORY | L_CREATE | L_EXCLUSIVE; 1133 rc = vfs_lookup_internal(path, lflag, NULL, NULL); 1134 fibril_rwlock_write_unlock(&namespace_rwlock); 1135 free(path); 1136 async_answer_0(rid, rc); 1137 } 1138 1139 void vfs_unlink(ipc_callid_t rid, ipc_call_t *request) 1140 { 1141 int lflag = IPC_GET_ARG1(*request); 1142 1143 char *path; 1144 int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL); 1145 if (rc != EOK) { 1146 async_answer_0(rid, rc); 1147 return; 1148 } 1149 1150 fibril_rwlock_write_lock(&namespace_rwlock); 1151 lflag &= L_DIRECTORY; /* sanitize lflag */ 1152 vfs_lookup_res_t lr; 1153 rc = vfs_lookup_internal(path, lflag | L_UNLINK, &lr, NULL); 1154 free(path); 1155 if (rc != EOK) { 1156 fibril_rwlock_write_unlock(&namespace_rwlock); 1157 async_answer_0(rid, rc); 1158 return; 1159 } 1160 1161 /* 1162 * The name has already been unlinked by vfs_lookup_internal(). 1163 * We have to get and put the VFS node to ensure that it is 1164 * VFS_OUT_DESTROY'ed after the last reference to it is dropped. 1165 */ 1166 vfs_node_t *node = vfs_node_get(&lr); 1167 fibril_mutex_lock(&nodes_mutex); 1168 node->lnkcnt--; 1169 fibril_mutex_unlock(&nodes_mutex); 1170 fibril_rwlock_write_unlock(&namespace_rwlock); 1171 vfs_node_put(node); 1172 async_answer_0(rid, EOK); 1173 } 1174 1175 void vfs_rename(ipc_callid_t rid, ipc_call_t *request) 1176 { 1177 /* Retrieve the old path. */ 1178 char *old; 1179 int rc = async_data_write_accept((void **) &old, true, 0, 0, 0, NULL); 1180 if (rc != EOK) { 1181 async_answer_0(rid, rc); 1182 return; 1183 } 1184 1185 /* Retrieve the new path. */ 1186 char *new; 1187 rc = async_data_write_accept((void **) &new, true, 0, 0, 0, NULL); 1188 if (rc != EOK) { 1189 free(old); 1190 async_answer_0(rid, rc); 1191 return; 1192 } 1193 1194 size_t olen; 1195 size_t nlen; 1196 char *oldc = canonify(old, &olen); 1197 char *newc = canonify(new, &nlen); 1198 1199 if ((!oldc) || (!newc)) { 1200 async_answer_0(rid, EINVAL); 1201 free(old); 1202 free(new); 1203 return; 1204 } 1205 1206 oldc[olen] = '\0'; 1207 newc[nlen] = '\0'; 1208 1209 if ((!str_lcmp(newc, oldc, str_length(oldc))) && 1210 ((newc[str_length(oldc)] == '/') || 1211 (str_length(oldc) == 1) || 1212 (str_length(oldc) == str_length(newc)))) { 1213 /* 1214 * oldc is a prefix of newc and either 1215 * - newc continues with a / where oldc ends, or 1216 * - oldc was / itself, or 1217 * - oldc and newc are equal. 1218 */ 1219 async_answer_0(rid, EINVAL); 1220 free(old); 1221 free(new); 1222 return; 1223 } 1224 1225 vfs_lookup_res_t old_lr; 1226 vfs_lookup_res_t new_lr; 1227 vfs_lookup_res_t new_par_lr; 1228 fibril_rwlock_write_lock(&namespace_rwlock); 1229 1230 /* Lookup the node belonging to the old file name. */ 1231 rc = vfs_lookup_internal(oldc, L_NONE, &old_lr, NULL); 1232 if (rc != EOK) { 1233 fibril_rwlock_write_unlock(&namespace_rwlock); 1234 async_answer_0(rid, rc); 1235 free(old); 1236 free(new); 1237 return; 1238 } 1239 1240 vfs_node_t *old_node = vfs_node_get(&old_lr); 1241 if (!old_node) { 1242 fibril_rwlock_write_unlock(&namespace_rwlock); 1243 async_answer_0(rid, ENOMEM); 1244 free(old); 1245 free(new); 1246 return; 1247 } 1248 1249 /* Determine the path to the parent of the node with the new name. */ 1250 char *parentc = str_dup(newc); 1251 if (!parentc) { 1252 fibril_rwlock_write_unlock(&namespace_rwlock); 1253 vfs_node_put(old_node); 1254 async_answer_0(rid, rc); 1255 free(old); 1256 free(new); 1257 return; 1258 } 1259 1260 char *lastsl = str_rchr(parentc + 1, '/'); 1261 if (lastsl) 1262 *lastsl = '\0'; 1263 else 1264 parentc[1] = '\0'; 1265 1266 /* Lookup parent of the new file name. */ 1267 rc = vfs_lookup_internal(parentc, L_NONE, &new_par_lr, NULL); 1268 free(parentc); /* not needed anymore */ 1269 if (rc != EOK) { 1270 fibril_rwlock_write_unlock(&namespace_rwlock); 1271 vfs_node_put(old_node); 1272 async_answer_0(rid, rc); 1273 free(old); 1274 free(new); 1275 return; 1276 } 1277 1278 /* Check whether linking to the same file system instance. */ 1279 if ((old_node->fs_handle != new_par_lr.triplet.fs_handle) || 1280 (old_node->service_id != new_par_lr.triplet.service_id)) { 1281 fibril_rwlock_write_unlock(&namespace_rwlock); 1282 vfs_node_put(old_node); 1283 async_answer_0(rid, EXDEV); /* different file systems */ 1284 free(old); 1285 free(new); 1286 return; 1287 } 1288 1289 /* Destroy the old link for the new name. */ 1290 vfs_node_t *new_node = NULL; 1291 rc = vfs_lookup_internal(newc, L_UNLINK, &new_lr, NULL); 1292 1293 switch (rc) { 1294 case ENOENT: 1295 /* simply not in our way */ 1296 break; 1297 case EOK: 1298 new_node = vfs_node_get(&new_lr); 1299 if (!new_node) { 1300 fibril_rwlock_write_unlock(&namespace_rwlock); 1301 vfs_node_put(old_node); 1302 async_answer_0(rid, ENOMEM); 1303 free(old); 1304 free(new); 1305 return; 1306 } 1307 fibril_mutex_lock(&nodes_mutex); 1308 new_node->lnkcnt--; 1309 fibril_mutex_unlock(&nodes_mutex); 1310 break; 1311 default: 1312 fibril_rwlock_write_unlock(&namespace_rwlock); 1313 vfs_node_put(old_node); 1314 async_answer_0(rid, ENOTEMPTY); 1315 free(old); 1316 free(new); 1317 return; 1318 } 1319 1320 /* Create the new link for the new name. */ 1321 rc = vfs_lookup_internal(newc, L_LINK, NULL, NULL, old_node->index); 1322 if (rc != EOK) { 1323 fibril_rwlock_write_unlock(&namespace_rwlock); 1324 vfs_node_put(old_node); 1325 if (new_node) 1326 vfs_node_put(new_node); 1327 async_answer_0(rid, rc); 1328 free(old); 1329 free(new); 1330 return; 1331 } 1332 1333 fibril_mutex_lock(&nodes_mutex); 1334 old_node->lnkcnt++; 1335 fibril_mutex_unlock(&nodes_mutex); 1336 1337 /* Destroy the link for the old name. */ 1338 rc = vfs_lookup_internal(oldc, L_UNLINK, NULL, NULL); 1339 if (rc != EOK) { 1340 fibril_rwlock_write_unlock(&namespace_rwlock); 1341 vfs_node_put(old_node); 1342 if (new_node) 1343 vfs_node_put(new_node); 1344 async_answer_0(rid, rc); 1345 free(old); 1346 free(new); 1347 return; 1348 } 1349 1350 fibril_mutex_lock(&nodes_mutex); 1351 old_node->lnkcnt--; 1352 fibril_mutex_unlock(&nodes_mutex); 1353 fibril_rwlock_write_unlock(&namespace_rwlock); 1354 vfs_node_put(old_node); 1355 1356 if (new_node) 1357 vfs_node_put(new_node); 1358 1359 free(old); 1360 free(new); 1361 async_answer_0(rid, EOK); 1362 } 1363 1364 void vfs_dup(ipc_callid_t rid, ipc_call_t *request) 1365 { 1366 int oldfd = IPC_GET_ARG1(*request); 1367 int newfd = IPC_GET_ARG2(*request); 1368 1369 /* If the file descriptors are the same, do nothing. */ 1370 if (oldfd == newfd) { 1371 async_answer_1(rid, EOK, newfd); 1372 return; 1373 } 1374 1375 /* Lookup the file structure corresponding to oldfd. */ 1376 vfs_file_t *oldfile = vfs_file_get(oldfd); 1377 if (!oldfile) { 1378 async_answer_0(rid, EBADF); 1379 return; 1380 } 1381 1382 /* 1383 * Lock the open file structure so that no other thread can manipulate 1384 * the same open file at a time. 1385 */ 1386 fibril_mutex_lock(&oldfile->lock); 1387 1388 /* Make sure newfd is closed. */ 1389 (void) vfs_fd_free(newfd); 1390 1391 /* Assign the old file to newfd. */ 1392 int ret = vfs_fd_assign(oldfile, newfd); 1393 fibril_mutex_unlock(&oldfile->lock); 1394 vfs_file_put(oldfile); 1395 1396 if (ret != EOK) 1397 async_answer_0(rid, ret); 1398 else 1399 async_answer_1(rid, EOK, newfd); 1400 } 1401 1402 void vfs_wait_handle(ipc_callid_t rid, ipc_call_t *request) 1403 { 1404 int fd = vfs_wait_handle_internal(); 1405 async_answer_1(rid, EOK, fd); 1406 } 1407 1408 void vfs_get_mtab(ipc_callid_t rid, ipc_call_t *request) 1409 { 1410 ipc_callid_t callid; 1411 ipc_call_t data; 1412 sysarg_t rc = EOK; 1413 size_t len; 1414 1415 fibril_mutex_lock(&mtab_list_lock); 1416 1417 /* Send to the caller the number of mounted filesystems */ 1418 callid = async_get_call(&data); 1419 if (IPC_GET_IMETHOD(data) != VFS_IN_PING) { 1420 rc = ENOTSUP; 1421 async_answer_0(callid, rc); 1422 goto exit; 1423 } 1424 async_answer_1(callid, EOK, mtab_size); 1425 1426 list_foreach(mtab_list, link, mtab_ent_t, mtab_ent) { 1427 rc = ENOTSUP; 1428 1429 if (!async_data_read_receive(&callid, &len)) { 1430 async_answer_0(callid, rc); 1431 goto exit; 1432 } 1433 1434 (void) async_data_read_finalize(callid, mtab_ent->mp, 1435 str_size(mtab_ent->mp)); 1436 1437 if (!async_data_read_receive(&callid, &len)) { 1438 async_answer_0(callid, rc); 1439 goto exit; 1440 } 1441 1442 (void) async_data_read_finalize(callid, mtab_ent->opts, 1443 str_size(mtab_ent->opts)); 1444 1445 if (!async_data_read_receive(&callid, &len)) { 1446 async_answer_0(callid, rc); 1447 goto exit; 1448 } 1449 1450 (void) async_data_read_finalize(callid, mtab_ent->fs_name, 1451 str_size(mtab_ent->fs_name)); 1452 1453 callid = async_get_call(&data); 1454 1455 if (IPC_GET_IMETHOD(data) != VFS_IN_PING) { 1456 async_answer_0(callid, rc); 1457 goto exit; 1458 } 1459 1460 rc = EOK; 1461 async_answer_2(callid, rc, mtab_ent->instance, 1462 mtab_ent->service_id); 1463 } 1464 1465 exit: 1466 fibril_mutex_unlock(&mtab_list_lock); 1467 async_answer_0(rid, rc); 1468 } 1469 1470 void vfs_statfs(ipc_callid_t rid, ipc_call_t *request) 1471 { 1472 char *path; 1473 int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL); 1474 if (rc != EOK) { 1475 async_answer_0(rid, rc); 1476 return; 1477 } 1478 1479 ipc_callid_t callid; 1480 if (!async_data_read_receive(&callid, NULL)) { 1481 free(path); 1482 async_answer_0(callid, EINVAL); 1483 async_answer_0(rid, EINVAL); 1484 return; 1485 } 1486 1487 vfs_lookup_res_t lr; 1488 fibril_rwlock_read_lock(&namespace_rwlock); 1489 rc = vfs_lookup_internal(path, L_NONE, &lr, NULL); 1490 free(path); 1491 if (rc != EOK) { 1492 fibril_rwlock_read_unlock(&namespace_rwlock); 1493 async_answer_0(callid, rc); 1494 async_answer_0(rid, rc); 1495 return; 1496 } 1497 vfs_node_t *node = vfs_node_get(&lr); 1498 if (!node) { 1499 fibril_rwlock_read_unlock(&namespace_rwlock); 1500 async_answer_0(callid, ENOMEM); 1501 async_answer_0(rid, ENOMEM); 1502 return; 1503 } 1504 1505 fibril_rwlock_read_unlock(&namespace_rwlock); 1506 1507 async_exch_t *exch = vfs_exchange_grab(node->fs_handle); 1508 1509 aid_t msg; 1510 msg = async_send_3(exch, VFS_OUT_STATFS, node->service_id, 1511 node->index, false, NULL); 1512 async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME); 1513 1514 vfs_exchange_release(exch); 1515 1516 sysarg_t rv; 1517 async_wait_for(msg, &rv); 1518 1519 async_answer_0(rid, rv); 1520 1521 vfs_node_put(node); 881 *out_fd = fd; 882 return EOK; 883 } 884 885 int vfs_op_write(int fd, aoff64_t pos, size_t *out_bytes) 886 { 887 return vfs_rdwr(fd, pos, false, rdwr_ipc_client, out_bytes); 1522 888 } 1523 889
Note:
See TracChangeset
for help on using the changeset viewer.