Changes in uspace/srv/vfs/vfs_ops.c [4cac2d69:08232ee] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/vfs/vfs_ops.c
r4cac2d69 r08232ee 92 92 } 93 93 94 rc = vfs_lookup_internal(mp, L_ MP, &mp_res, NULL);94 rc = vfs_lookup_internal(mp, L_DIRECTORY, &mp_res, NULL); 95 95 if (rc != EOK) { 96 96 /* The lookup failed for some reason. */ … … 266 266 267 267 /* We want the client to send us the mount point. */ 268 char *mp; 269 int rc = async_data_write_accept((void **) &mp, true, 0, MAX_PATH_LEN, 270 0, NULL); 271 if (rc != EOK) { 272 ipc_answer_0(rid, rc); 273 return; 274 } 268 ipc_callid_t callid; 269 size_t size; 270 if (!async_data_write_receive(&callid, &size)) { 271 ipc_answer_0(callid, EINVAL); 272 ipc_answer_0(rid, EINVAL); 273 return; 274 } 275 276 /* Check whether size is reasonable wrt. the mount point. */ 277 if ((size < 1) || (size > MAX_PATH_LEN)) { 278 ipc_answer_0(callid, EINVAL); 279 ipc_answer_0(rid, EINVAL); 280 return; 281 } 282 283 /* Allocate buffer for the mount point data being received. */ 284 char *mp = malloc(size + 1); 285 if (!mp) { 286 ipc_answer_0(callid, ENOMEM); 287 ipc_answer_0(rid, ENOMEM); 288 return; 289 } 290 291 /* Deliver the mount point. */ 292 ipcarg_t retval = async_data_write_finalize(callid, mp, size); 293 if (retval != EOK) { 294 ipc_answer_0(rid, retval); 295 free(mp); 296 return; 297 } 298 mp[size] = '\0'; 275 299 276 300 /* Now we expect to receive the mount options. */ 277 char *opts; 278 rc = async_data_write_accept((void **) &opts, true, 0, MAX_MNTOPTS_LEN, 279 0, NULL); 280 if (rc != EOK) { 301 if (!async_data_write_receive(&callid, &size)) { 302 ipc_answer_0(callid, EINVAL); 303 ipc_answer_0(rid, EINVAL); 281 304 free(mp); 282 ipc_answer_0(rid, rc); 283 return; 284 } 305 return; 306 } 307 308 /* Check the offered options size. */ 309 if (size > MAX_MNTOPTS_LEN) { 310 ipc_answer_0(callid, EINVAL); 311 ipc_answer_0(rid, EINVAL); 312 free(mp); 313 return; 314 } 315 316 /* Allocate buffer for the mount options. */ 317 char *opts = (char *) malloc(size + 1); 318 if (!opts) { 319 ipc_answer_0(callid, ENOMEM); 320 ipc_answer_0(rid, ENOMEM); 321 free(mp); 322 return; 323 } 324 325 /* Deliver the mount options. */ 326 retval = async_data_write_finalize(callid, opts, size); 327 if (retval != EOK) { 328 ipc_answer_0(rid, retval); 329 free(mp); 330 free(opts); 331 return; 332 } 333 opts[size] = '\0'; 285 334 286 335 /* … … 288 337 * system. 289 338 */ 290 char *fs_name; 291 rc = async_data_write_accept((void **) &fs_name, true, 0, FS_NAME_MAXLEN, 292 0, NULL); 293 if (rc != EOK) { 339 if (!async_data_write_receive(&callid, &size)) { 340 ipc_answer_0(callid, EINVAL); 341 ipc_answer_0(rid, EINVAL); 294 342 free(mp); 295 343 free(opts); 296 ipc_answer_0(rid, rc); 297 return; 298 } 299 344 return; 345 } 346 347 /* 348 * Don't receive more than is necessary for storing a full file system 349 * name. 350 */ 351 if ((size < 1) || (size > FS_NAME_MAXLEN)) { 352 ipc_answer_0(callid, EINVAL); 353 ipc_answer_0(rid, EINVAL); 354 free(mp); 355 free(opts); 356 return; 357 } 358 359 /* 360 * Allocate buffer for file system name. 361 */ 362 char *fs_name = (char *) malloc(size + 1); 363 if (fs_name == NULL) { 364 ipc_answer_0(callid, ENOMEM); 365 ipc_answer_0(rid, ENOMEM); 366 free(mp); 367 free(opts); 368 return; 369 } 370 371 /* Deliver the file system name. */ 372 retval = async_data_write_finalize(callid, fs_name, size); 373 if (retval != EOK) { 374 ipc_answer_0(rid, retval); 375 free(mp); 376 free(opts); 377 free(fs_name); 378 return; 379 } 380 fs_name[size] = '\0'; 381 300 382 /* 301 383 * Wait for IPC_M_PING so that we can return an error if we don't know … … 303 385 */ 304 386 ipc_call_t data; 305 ipc_callid_tcallid = async_get_call(&data);387 callid = async_get_call(&data); 306 388 if (IPC_GET_METHOD(data) != IPC_M_PING) { 307 389 ipc_answer_0(callid, ENOTSUP); … … 347 429 } 348 430 349 void vfs_unmount(ipc_callid_t rid, ipc_call_t *request)350 {351 int rc;352 char *mp;353 vfs_lookup_res_t mp_res;354 vfs_lookup_res_t mr_res;355 vfs_node_t *mp_node;356 vfs_node_t *mr_node;357 int phone;358 359 /*360 * Receive the mount point path.361 */362 rc = async_data_write_accept((void **) &mp, true, 0, MAX_PATH_LEN,363 0, NULL);364 if (rc != EOK)365 ipc_answer_0(rid, rc);366 367 /*368 * Taking the namespace lock will do two things for us. First, it will369 * prevent races with other lookup operations. Second, it will stop new370 * references to already existing VFS nodes and creation of new VFS371 * nodes. This is because new references are added as a result of some372 * lookup operation or at least of some operation which is protected by373 * the namespace lock.374 */375 fibril_rwlock_write_lock(&namespace_rwlock);376 377 /*378 * Lookup the mounted root and instantiate it.379 */380 rc = vfs_lookup_internal(mp, L_ROOT, &mr_res, NULL);381 if (rc != EOK) {382 fibril_rwlock_write_unlock(&namespace_rwlock);383 free(mp);384 ipc_answer_0(rid, rc);385 return;386 }387 mr_node = vfs_node_get(&mr_res);388 if (!mr_node) {389 fibril_rwlock_write_unlock(&namespace_rwlock);390 free(mp);391 ipc_answer_0(rid, ENOMEM);392 return;393 }394 395 /*396 * Count the total number of references for the mounted file system. We397 * are expecting at least two. One which we got above and one which we398 * got when the file system was mounted. If we find more, it means that399 * the file system cannot be gracefully unmounted at the moment because400 * someone is working with it.401 */402 if (vfs_nodes_refcount_sum_get(mr_node->fs_handle,403 mr_node->dev_handle) != 2) {404 fibril_rwlock_write_unlock(&namespace_rwlock);405 vfs_node_put(mr_node);406 free(mp);407 ipc_answer_0(rid, EBUSY);408 return;409 }410 411 if (str_cmp(mp, "/") == 0) {412 413 /*414 * Unmounting the root file system.415 *416 * In this case, there is no mount point node and we send417 * VFS_OUT_UNMOUNTED directly to the mounted file system.418 */419 420 free(mp);421 phone = vfs_grab_phone(mr_node->fs_handle);422 rc = async_req_1_0(phone, VFS_OUT_UNMOUNTED,423 mr_node->dev_handle);424 vfs_release_phone(phone);425 if (rc != EOK) {426 fibril_rwlock_write_unlock(&namespace_rwlock);427 vfs_node_put(mr_node);428 ipc_answer_0(rid, rc);429 return;430 }431 rootfs.fs_handle = 0;432 rootfs.dev_handle = 0;433 } else {434 435 /*436 * Unmounting a non-root file system.437 *438 * We have a regular mount point node representing the parent439 * file system, so we delegate the operation to it.440 */441 442 rc = vfs_lookup_internal(mp, L_MP, &mp_res, NULL);443 free(mp);444 if (rc != EOK) {445 fibril_rwlock_write_unlock(&namespace_rwlock);446 vfs_node_put(mr_node);447 ipc_answer_0(rid, rc);448 return;449 }450 vfs_node_t *mp_node = vfs_node_get(&mp_res);451 if (!mp_node) {452 fibril_rwlock_write_unlock(&namespace_rwlock);453 vfs_node_put(mr_node);454 ipc_answer_0(rid, ENOMEM);455 return;456 }457 458 phone = vfs_grab_phone(mp_node->fs_handle);459 rc = async_req_2_0(phone, VFS_OUT_UNMOUNT, mp_node->dev_handle,460 mp_node->index);461 vfs_release_phone(phone);462 if (rc != EOK) {463 fibril_rwlock_write_unlock(&namespace_rwlock);464 vfs_node_put(mp_node);465 vfs_node_put(mr_node);466 ipc_answer_0(rid, rc);467 return;468 }469 470 /* Drop the reference we got above. */471 vfs_node_put(mp_node);472 /* Drop the reference from when the file system was mounted. */473 vfs_node_put(mp_node);474 }475 476 477 /*478 * All went well, the mounted file system was successfully unmounted.479 * The only thing left is to forget the unmounted root VFS node.480 */481 vfs_node_forget(mr_node);482 483 fibril_rwlock_write_unlock(&namespace_rwlock);484 ipc_answer_0(rid, EOK);485 }486 487 431 void vfs_open(ipc_callid_t rid, ipc_call_t *request) 488 432 { … … 510 454 /* 511 455 * Make sure that we are called with exactly one of L_FILE and 512 * L_DIRECTORY. Make sure that the user does not pass L_OPEN, 513 * L_ROOT or L_MP. 456 * L_DIRECTORY. Make sure that the user does not pass L_OPEN. 514 457 */ 515 458 if (((lflag & (L_FILE | L_DIRECTORY)) == 0) || 516 459 ((lflag & (L_FILE | L_DIRECTORY)) == (L_FILE | L_DIRECTORY)) || 517 ( lflag & (L_OPEN | L_ROOT | L_MP))) {460 ((lflag & L_OPEN) != 0)) { 518 461 ipc_answer_0(rid, EINVAL); 519 462 return; … … 525 468 lflag |= L_EXCLUSIVE; 526 469 527 char *path; 528 int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL); 529 if (rc != EOK) { 530 ipc_answer_0(rid, rc); 531 return; 532 } 470 ipc_callid_t callid; 471 if (!async_data_write_receive(&callid, &len)) { 472 ipc_answer_0(callid, EINVAL); 473 ipc_answer_0(rid, EINVAL); 474 return; 475 } 476 477 char *path = malloc(len + 1); 478 if (!path) { 479 ipc_answer_0(callid, ENOMEM); 480 ipc_answer_0(rid, ENOMEM); 481 return; 482 } 483 484 int rc; 485 if ((rc = async_data_write_finalize(callid, path, len))) { 486 ipc_answer_0(rid, rc); 487 free(path); 488 return; 489 } 490 path[len] = '\0'; 533 491 534 492 /* … … 721 679 } 722 680 723 int vfs_close_internal(vfs_file_t *file)681 static int vfs_close_internal(vfs_file_t *file) 724 682 { 725 683 /* … … 798 756 799 757 /* 758 * Now we need to receive a call with client's 759 * IPC_M_DATA_READ/IPC_M_DATA_WRITE request. 760 */ 761 ipc_callid_t callid; 762 int res; 763 if (read) 764 res = async_data_read_receive(&callid, NULL); 765 else 766 res = async_data_write_receive(&callid, NULL); 767 if (!res) { 768 ipc_answer_0(callid, EINVAL); 769 ipc_answer_0(rid, EINVAL); 770 return; 771 } 772 773 /* 800 774 * Lock the open file structure so that no other thread can manipulate 801 775 * the same open file at a time. … … 821 795 } 822 796 823 int fs_phone = vfs_grab_phone(file->node->fs_handle); 824 825 /* 826 * Make a VFS_READ/VFS_WRITE request at the destination FS server 827 * and forward the IPC_M_DATA_READ/IPC_M_DATA_WRITE request to the 797 int fs_phone = vfs_grab_phone(file->node->fs_handle); 798 799 /* Make a VFS_READ/VFS_WRITE request at the destination FS server. */ 800 aid_t msg; 801 ipc_call_t answer; 802 if (!read && file->append) 803 file->pos = file->node->size; 804 msg = async_send_3(fs_phone, read ? VFS_OUT_READ : VFS_OUT_WRITE, 805 file->node->dev_handle, file->node->index, file->pos, &answer); 806 807 /* 808 * Forward the IPC_M_DATA_READ/IPC_M_DATA_WRITE request to the 828 809 * destination FS server. The call will be routed as if sent by 829 810 * ourselves. Note that call arguments are immutable in this case so we 830 811 * don't have to bother. 831 812 */ 813 ipc_forward_fast(callid, fs_phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME); 814 815 /* Wait for reply from the FS server. */ 832 816 ipcarg_t rc; 833 ipc_call_t answer; 834 if (read) { 835 if (file->append) 836 file->pos = file->node->size; 837 838 rc = async_data_read_forward_3_1(fs_phone, VFS_OUT_READ, 839 file->node->dev_handle, file->node->index, file->pos, 840 &answer); 841 } else { 842 rc = async_data_write_forward_3_1(fs_phone, VFS_OUT_WRITE, 843 file->node->dev_handle, file->node->index, file->pos, 844 &answer); 845 } 817 async_wait_for(msg, &rc); 846 818 847 819 vfs_release_phone(fs_phone); 848 820 849 821 size_t bytes = IPC_GET_ARG1(answer); 850 822 851 823 if (file->node->type == VFS_NODE_DIRECTORY) 852 824 fibril_rwlock_read_unlock(&namespace_rwlock); … … 1010 982 void vfs_stat(ipc_callid_t rid, ipc_call_t *request) 1011 983 { 1012 char *path; 1013 int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL); 1014 if (rc != EOK) { 1015 ipc_answer_0(rid, rc); 1016 return; 1017 } 1018 984 size_t len; 1019 985 ipc_callid_t callid; 986 987 if (!async_data_write_receive(&callid, &len)) { 988 ipc_answer_0(callid, EINVAL); 989 ipc_answer_0(rid, EINVAL); 990 return; 991 } 992 char *path = malloc(len + 1); 993 if (!path) { 994 ipc_answer_0(callid, ENOMEM); 995 ipc_answer_0(rid, ENOMEM); 996 return; 997 } 998 int rc; 999 if ((rc = async_data_write_finalize(callid, path, len))) { 1000 ipc_answer_0(rid, rc); 1001 free(path); 1002 return; 1003 } 1004 path[len] = '\0'; 1005 1020 1006 if (!async_data_read_receive(&callid, NULL)) { 1021 1007 free(path); … … 1063 1049 { 1064 1050 int mode = IPC_GET_ARG1(*request); 1065 1066 char *path; 1067 int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL); 1068 if (rc != EOK) { 1069 ipc_answer_0(rid, rc); 1070 return; 1071 } 1072 1051 1052 size_t len; 1053 ipc_callid_t callid; 1054 1055 if (!async_data_write_receive(&callid, &len)) { 1056 ipc_answer_0(callid, EINVAL); 1057 ipc_answer_0(rid, EINVAL); 1058 return; 1059 } 1060 char *path = malloc(len + 1); 1061 if (!path) { 1062 ipc_answer_0(callid, ENOMEM); 1063 ipc_answer_0(rid, ENOMEM); 1064 return; 1065 } 1066 int rc; 1067 if ((rc = async_data_write_finalize(callid, path, len))) { 1068 ipc_answer_0(rid, rc); 1069 free(path); 1070 return; 1071 } 1072 path[len] = '\0'; 1073 1073 1074 /* Ignore mode for now. */ 1074 1075 (void) mode; … … 1085 1086 { 1086 1087 int lflag = IPC_GET_ARG1(*request); 1087 1088 char *path; 1089 int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL); 1090 if (rc != EOK) { 1091 ipc_answer_0(rid, rc); 1092 return; 1093 } 1088 1089 size_t len; 1090 ipc_callid_t callid; 1091 1092 if (!async_data_write_receive(&callid, &len)) { 1093 ipc_answer_0(callid, EINVAL); 1094 ipc_answer_0(rid, EINVAL); 1095 return; 1096 } 1097 char *path = malloc(len + 1); 1098 if (!path) { 1099 ipc_answer_0(callid, ENOMEM); 1100 ipc_answer_0(rid, ENOMEM); 1101 return; 1102 } 1103 int rc; 1104 if ((rc = async_data_write_finalize(callid, path, len))) { 1105 ipc_answer_0(rid, rc); 1106 free(path); 1107 return; 1108 } 1109 path[len] = '\0'; 1094 1110 1095 1111 fibril_rwlock_write_lock(&namespace_rwlock); … … 1120 1136 void vfs_rename(ipc_callid_t rid, ipc_call_t *request) 1121 1137 { 1138 size_t olen, nlen; 1139 ipc_callid_t callid; 1140 int rc; 1141 1122 1142 /* Retrieve the old path. */ 1123 char *old; 1124 int rc = async_data_write_accept((void **) &old, true, 0, 0, 0, NULL); 1125 if (rc != EOK) { 1126 ipc_answer_0(rid, rc); 1127 return; 1128 } 1143 if (!async_data_write_receive(&callid, &olen)) { 1144 ipc_answer_0(callid, EINVAL); 1145 ipc_answer_0(rid, EINVAL); 1146 return; 1147 } 1148 char *old = malloc(olen + 1); 1149 if (!old) { 1150 ipc_answer_0(callid, ENOMEM); 1151 ipc_answer_0(rid, ENOMEM); 1152 return; 1153 } 1154 if ((rc = async_data_write_finalize(callid, old, olen))) { 1155 ipc_answer_0(rid, rc); 1156 free(old); 1157 return; 1158 } 1159 old[olen] = '\0'; 1129 1160 1130 1161 /* Retrieve the new path. */ 1131 char *new;1132 rc = async_data_write_accept((void **) &new, true, 0, 0, 0, NULL);1133 if (rc != EOK) {1162 if (!async_data_write_receive(&callid, &nlen)) { 1163 ipc_answer_0(callid, EINVAL); 1164 ipc_answer_0(rid, EINVAL); 1134 1165 free(old); 1135 ipc_answer_0(rid, rc); 1136 return; 1137 } 1138 1139 size_t olen; 1140 size_t nlen; 1166 return; 1167 } 1168 char *new = malloc(nlen + 1); 1169 if (!new) { 1170 ipc_answer_0(callid, ENOMEM); 1171 ipc_answer_0(rid, ENOMEM); 1172 free(old); 1173 return; 1174 } 1175 if ((rc = async_data_write_finalize(callid, new, nlen))) { 1176 ipc_answer_0(rid, rc); 1177 free(old); 1178 free(new); 1179 return; 1180 } 1181 new[nlen] = '\0'; 1182 1141 1183 char *oldc = canonify(old, &olen); 1142 1184 char *newc = canonify(new, &nlen); 1143 1144 if ((!oldc) || (!newc)) { 1185 if (!oldc || !newc) { 1145 1186 ipc_answer_0(rid, EINVAL); 1146 1187 free(old); … … 1148 1189 return; 1149 1190 } 1150 1151 1191 oldc[olen] = '\0'; 1152 1192 newc[nlen] = '\0'; 1153 1154 1193 if ((!str_lcmp(newc, oldc, str_length(oldc))) && 1155 1194 ((newc[str_length(oldc)] == '/') || … … 1172 1211 vfs_lookup_res_t new_par_lr; 1173 1212 fibril_rwlock_write_lock(&namespace_rwlock); 1174 1175 1213 /* Lookup the node belonging to the old file name. */ 1176 1214 rc = vfs_lookup_internal(oldc, L_NONE, &old_lr, NULL); … … 1182 1220 return; 1183 1221 } 1184 1185 1222 vfs_node_t *old_node = vfs_node_get(&old_lr); 1186 1223 if (!old_node) { … … 1191 1228 return; 1192 1229 } 1193 1194 1230 /* Determine the path to the parent of the node with the new name. */ 1195 1231 char *parentc = str_dup(newc); … … 1201 1237 return; 1202 1238 } 1203 1204 1239 char *lastsl = str_rchr(parentc + 1, '/'); 1205 1240 if (lastsl) … … 1207 1242 else 1208 1243 parentc[1] = '\0'; 1209 1210 1244 /* Lookup parent of the new file name. */ 1211 1245 rc = vfs_lookup_internal(parentc, L_NONE, &new_par_lr, NULL); … … 1218 1252 return; 1219 1253 } 1220 1221 1254 /* Check whether linking to the same file system instance. */ 1222 1255 if ((old_node->fs_handle != new_par_lr.triplet.fs_handle) || … … 1228 1261 return; 1229 1262 } 1230 1231 1263 /* Destroy the old link for the new name. */ 1232 1264 vfs_node_t *new_node = NULL; 1233 1265 rc = vfs_lookup_internal(newc, L_UNLINK, &new_lr, NULL); 1234 1235 1266 switch (rc) { 1236 1267 case ENOENT: … … 1257 1288 return; 1258 1289 } 1259 1260 1290 /* Create the new link for the new name. */ 1261 1291 rc = vfs_lookup_internal(newc, L_LINK, NULL, NULL, old_node->index); … … 1269 1299 return; 1270 1300 } 1271 1272 1301 fibril_mutex_lock(&nodes_mutex); 1273 1302 old_node->lnkcnt++; 1274 1303 fibril_mutex_unlock(&nodes_mutex); 1275 1276 1304 /* Destroy the link for the old name. */ 1277 1305 rc = vfs_lookup_internal(oldc, L_UNLINK, NULL, NULL); … … 1286 1314 return; 1287 1315 } 1288 1289 1316 fibril_mutex_lock(&nodes_mutex); 1290 1317 old_node->lnkcnt--; … … 1292 1319 fibril_rwlock_write_unlock(&namespace_rwlock); 1293 1320 vfs_node_put(old_node); 1294 1295 1321 if (new_node) 1296 1322 vfs_node_put(new_node); 1297 1298 1323 free(old); 1299 1324 free(new);
Note:
See TracChangeset
for help on using the changeset viewer.