Changes in uspace/srv/vfs/vfs_ops.c [2b88074b:b4cbef1] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/vfs/vfs_ops.c
r2b88074b rb4cbef1 44 44 #include <string.h> 45 45 #include <bool.h> 46 #include <fibril_sync .h>46 #include <fibril_synch.h> 47 47 #include <adt/list.h> 48 48 #include <unistd.h> … … 92 92 } 93 93 94 rc = vfs_lookup_internal(mp, L_ DIRECTORY, &mp_res, NULL);94 rc = vfs_lookup_internal(mp, L_MP, &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 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); 268 char *mp; 269 int rc = async_string_receive(&mp, MAX_PATH_LEN, NULL); 270 if (rc != EOK) { 271 ipc_answer_0(rid, rc); 272 return; 273 } 274 275 /* Now we expect to receive the mount options. */ 276 char *opts; 277 rc = async_string_receive(&opts, MAX_MNTOPTS_LEN, NULL); 278 if (rc != EOK) { 295 279 free(mp); 296 return; 297 } 298 mp[size] = '\0'; 299 300 /* Now we expect to receive the mount options. */ 301 if (!async_data_write_receive(&callid, &size)) { 302 ipc_answer_0(callid, EINVAL); 303 ipc_answer_0(rid, EINVAL); 304 free(mp); 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); 280 ipc_answer_0(rid, rc); 281 return; 282 } 283 284 /* 285 * Now, we expect the client to send us data with the name of the file 286 * system. 287 */ 288 char *fs_name; 289 rc = async_string_receive(&fs_name, FS_NAME_MAXLEN, NULL); 290 if (rc != EOK) { 329 291 free(mp); 330 292 free(opts); 331 return; 332 } 333 opts[size] = '\0'; 334 335 /* 336 * Now, we expect the client to send us data with the name of the file 337 * system. 338 */ 339 if (!async_data_write_receive(&callid, &size)) { 340 ipc_answer_0(callid, EINVAL); 341 ipc_answer_0(rid, EINVAL); 342 free(mp); 343 free(opts); 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 293 ipc_answer_0(rid, rc); 294 return; 295 } 296 382 297 /* 383 298 * Wait for IPC_M_PING so that we can return an error if we don't know … … 385 300 */ 386 301 ipc_call_t data; 387 callid = async_get_call(&data);302 ipc_callid_t callid = async_get_call(&data); 388 303 if (IPC_GET_METHOD(data) != IPC_M_PING) { 389 304 ipc_answer_0(callid, ENOTSUP); … … 429 344 } 430 345 346 void vfs_unmount(ipc_callid_t rid, ipc_call_t *request) 347 { 348 int rc; 349 char *mp; 350 vfs_lookup_res_t mp_res; 351 vfs_lookup_res_t mr_res; 352 vfs_node_t *mp_node; 353 vfs_node_t *mr_node; 354 int phone; 355 356 /* 357 * Receive the mount point path. 358 */ 359 rc = async_string_receive(&mp, MAX_PATH_LEN, NULL); 360 if (rc != EOK) 361 ipc_answer_0(rid, rc); 362 363 /* 364 * Taking the namespace lock will do two things for us. First, it will 365 * prevent races with other lookup operations. Second, it will stop new 366 * references to already existing VFS nodes and creation of new VFS 367 * nodes. This is because new references are added as a result of some 368 * lookup operation or at least of some operation which is protected by 369 * the namespace lock. 370 */ 371 fibril_rwlock_write_lock(&namespace_rwlock); 372 373 /* 374 * Lookup the mounted root and instantiate it. 375 */ 376 rc = vfs_lookup_internal(mp, L_ROOT, &mr_res, NULL); 377 if (rc != EOK) { 378 fibril_rwlock_write_unlock(&namespace_rwlock); 379 free(mp); 380 ipc_answer_0(rid, rc); 381 return; 382 } 383 mr_node = vfs_node_get(&mr_res); 384 if (!mr_node) { 385 fibril_rwlock_write_unlock(&namespace_rwlock); 386 free(mp); 387 ipc_answer_0(rid, ENOMEM); 388 return; 389 } 390 391 /* 392 * Count the total number of references for the mounted file system. We 393 * are expecting at least two. One which we got above and one which we 394 * got when the file system was mounted. If we find more, it means that 395 * the file system cannot be gracefully unmounted at the moment because 396 * someone is working with it. 397 */ 398 if (vfs_nodes_refcount_sum_get(mr_node->fs_handle, 399 mr_node->dev_handle) != 2) { 400 fibril_rwlock_write_unlock(&namespace_rwlock); 401 vfs_node_put(mr_node); 402 free(mp); 403 ipc_answer_0(rid, EBUSY); 404 return; 405 } 406 407 if (str_cmp(mp, "/") == 0) { 408 409 /* 410 * Unmounting the root file system. 411 * 412 * In this case, there is no mount point node and we send 413 * VFS_OUT_UNMOUNTED directly to the mounted file system. 414 */ 415 416 free(mp); 417 phone = vfs_grab_phone(mr_node->fs_handle); 418 rc = async_req_1_0(phone, VFS_OUT_UNMOUNTED, 419 mr_node->dev_handle); 420 vfs_release_phone(phone); 421 if (rc != EOK) { 422 fibril_rwlock_write_unlock(&namespace_rwlock); 423 vfs_node_put(mr_node); 424 ipc_answer_0(rid, rc); 425 return; 426 } 427 rootfs.fs_handle = 0; 428 rootfs.dev_handle = 0; 429 } else { 430 431 /* 432 * Unmounting a non-root file system. 433 * 434 * We have a regular mount point node representing the parent 435 * file system, so we delegate the operation to it. 436 */ 437 438 rc = vfs_lookup_internal(mp, L_MP, &mp_res, NULL); 439 free(mp); 440 if (rc != EOK) { 441 fibril_rwlock_write_unlock(&namespace_rwlock); 442 vfs_node_put(mr_node); 443 ipc_answer_0(rid, rc); 444 return; 445 } 446 vfs_node_t *mp_node = vfs_node_get(&mp_res); 447 if (!mp_node) { 448 fibril_rwlock_write_unlock(&namespace_rwlock); 449 vfs_node_put(mr_node); 450 ipc_answer_0(rid, ENOMEM); 451 return; 452 } 453 454 phone = vfs_grab_phone(mp_node->fs_handle); 455 rc = async_req_2_0(phone, VFS_OUT_UNMOUNT, mp_node->dev_handle, 456 mp_node->index); 457 vfs_release_phone(phone); 458 if (rc != EOK) { 459 fibril_rwlock_write_unlock(&namespace_rwlock); 460 vfs_node_put(mp_node); 461 vfs_node_put(mr_node); 462 ipc_answer_0(rid, rc); 463 return; 464 } 465 466 /* Drop the reference we got above. */ 467 vfs_node_put(mp_node); 468 /* Drop the reference from when the file system was mounted. */ 469 vfs_node_put(mp_node); 470 } 471 472 473 /* 474 * All went well, the mounted file system was successfully unmounted. 475 * The only thing left is to forget the unmounted root VFS node. 476 */ 477 vfs_node_forget(mr_node); 478 479 fibril_rwlock_write_unlock(&namespace_rwlock); 480 ipc_answer_0(rid, EOK); 481 } 482 431 483 void vfs_open(ipc_callid_t rid, ipc_call_t *request) 432 484 { … … 454 506 /* 455 507 * Make sure that we are called with exactly one of L_FILE and 456 * L_DIRECTORY. Make sure that the user does not pass L_OPEN. 508 * L_DIRECTORY. Make sure that the user does not pass L_OPEN, 509 * L_ROOT or L_MP. 457 510 */ 458 511 if (((lflag & (L_FILE | L_DIRECTORY)) == 0) || 459 512 ((lflag & (L_FILE | L_DIRECTORY)) == (L_FILE | L_DIRECTORY)) || 460 ( (lflag & L_OPEN) != 0)) {513 (lflag & (L_OPEN | L_ROOT | L_MP))) { 461 514 ipc_answer_0(rid, EINVAL); 462 515 return; … … 468 521 lflag |= L_EXCLUSIVE; 469 522 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'; 523 char *path; 524 int rc = async_string_receive(&path, 0, NULL); 525 if (rc != EOK) { 526 ipc_answer_0(rid, rc); 527 return; 528 } 491 529 492 530 /* … … 679 717 } 680 718 681 staticint vfs_close_internal(vfs_file_t *file)719 int vfs_close_internal(vfs_file_t *file) 682 720 { 683 721 /* … … 756 794 757 795 /* 758 * Now we need to receive a call with client's759 * 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 else766 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 /*774 796 * Lock the open file structure so that no other thread can manipulate 775 797 * the same open file at a time. … … 795 817 } 796 818 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 819 int fs_phone = vfs_grab_phone(file->node->fs_handle); 820 821 /* 822 * Make a VFS_READ/VFS_WRITE request at the destination FS server 823 * and forward the IPC_M_DATA_READ/IPC_M_DATA_WRITE request to the 809 824 * destination FS server. The call will be routed as if sent by 810 825 * ourselves. Note that call arguments are immutable in this case so we 811 826 * don't have to bother. 812 827 */ 813 ipc_forward_fast(callid, fs_phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);814 815 /* Wait for reply from the FS server. */816 828 ipcarg_t rc; 817 async_wait_for(msg, &rc); 829 ipc_call_t answer; 830 if (read) { 831 if (file->append) 832 file->pos = file->node->size; 833 834 rc = async_data_read_forward_3_1(fs_phone, VFS_OUT_READ, 835 file->node->dev_handle, file->node->index, file->pos, 836 &answer); 837 } else { 838 rc = async_data_forward_3_1(fs_phone, VFS_OUT_WRITE, 839 file->node->dev_handle, file->node->index, file->pos, 840 &answer); 841 } 818 842 819 843 vfs_release_phone(fs_phone); 820 844 821 845 size_t bytes = IPC_GET_ARG1(answer); 822 846 823 847 if (file->node->type == VFS_NODE_DIRECTORY) 824 848 fibril_rwlock_read_unlock(&namespace_rwlock); … … 900 924 } 901 925 newpos = size + off; 926 file->pos = newpos; 902 927 fibril_mutex_unlock(&file->lock); 903 928 ipc_answer_1(rid, EOK, newpos); … … 981 1006 void vfs_stat(ipc_callid_t rid, ipc_call_t *request) 982 1007 { 983 size_t len; 1008 char *path; 1009 int rc = async_string_receive(&path, 0, NULL); 1010 if (rc != EOK) { 1011 ipc_answer_0(rid, rc); 1012 return; 1013 } 1014 984 1015 ipc_callid_t callid; 985 986 if (!async_data_write_receive(&callid, &len)) {987 ipc_answer_0(callid, EINVAL);988 ipc_answer_0(rid, EINVAL);989 return;990 }991 char *path = malloc(len + 1);992 if (!path) {993 ipc_answer_0(callid, ENOMEM);994 ipc_answer_0(rid, ENOMEM);995 return;996 }997 int rc;998 if ((rc = async_data_write_finalize(callid, path, len))) {999 ipc_answer_0(rid, rc);1000 free(path);1001 return;1002 }1003 path[len] = '\0';1004 1005 1016 if (!async_data_read_receive(&callid, NULL)) { 1006 1017 free(path); … … 1048 1059 { 1049 1060 int mode = IPC_GET_ARG1(*request); 1050 1051 size_t len; 1052 ipc_callid_t callid; 1053 1054 if (!async_data_write_receive(&callid, &len)) { 1055 ipc_answer_0(callid, EINVAL); 1056 ipc_answer_0(rid, EINVAL); 1057 return; 1058 } 1059 char *path = malloc(len + 1); 1060 if (!path) { 1061 ipc_answer_0(callid, ENOMEM); 1062 ipc_answer_0(rid, ENOMEM); 1063 return; 1064 } 1065 int rc; 1066 if ((rc = async_data_write_finalize(callid, path, len))) { 1067 ipc_answer_0(rid, rc); 1068 free(path); 1069 return; 1070 } 1071 path[len] = '\0'; 1072 1061 1062 char *path; 1063 int rc = async_string_receive(&path, 0, NULL); 1064 if (rc != EOK) { 1065 ipc_answer_0(rid, rc); 1066 return; 1067 } 1068 1073 1069 /* Ignore mode for now. */ 1074 1070 (void) mode; … … 1085 1081 { 1086 1082 int lflag = IPC_GET_ARG1(*request); 1087 1088 size_t len; 1089 ipc_callid_t callid; 1090 1091 if (!async_data_write_receive(&callid, &len)) { 1092 ipc_answer_0(callid, EINVAL); 1093 ipc_answer_0(rid, EINVAL); 1094 return; 1095 } 1096 char *path = malloc(len + 1); 1097 if (!path) { 1098 ipc_answer_0(callid, ENOMEM); 1099 ipc_answer_0(rid, ENOMEM); 1100 return; 1101 } 1102 int rc; 1103 if ((rc = async_data_write_finalize(callid, path, len))) { 1104 ipc_answer_0(rid, rc); 1105 free(path); 1106 return; 1107 } 1108 path[len] = '\0'; 1083 1084 char *path; 1085 int rc = async_string_receive(&path, 0, NULL); 1086 if (rc != EOK) { 1087 ipc_answer_0(rid, rc); 1088 return; 1089 } 1109 1090 1110 1091 fibril_rwlock_write_lock(&namespace_rwlock); … … 1135 1116 void vfs_rename(ipc_callid_t rid, ipc_call_t *request) 1136 1117 { 1137 size_t olen, nlen;1138 ipc_callid_t callid;1139 int rc;1140 1141 1118 /* Retrieve the old path. */ 1142 if (!async_data_write_receive(&callid, &olen)) { 1143 ipc_answer_0(callid, EINVAL); 1144 ipc_answer_0(rid, EINVAL); 1145 return; 1146 } 1147 char *old = malloc(olen + 1); 1148 if (!old) { 1149 ipc_answer_0(callid, ENOMEM); 1150 ipc_answer_0(rid, ENOMEM); 1151 return; 1152 } 1153 if ((rc = async_data_write_finalize(callid, old, olen))) { 1154 ipc_answer_0(rid, rc); 1119 char *old; 1120 int rc = async_string_receive(&old, 0, NULL); 1121 if (rc != EOK) { 1122 ipc_answer_0(rid, rc); 1123 return; 1124 } 1125 1126 /* Retrieve the new path. */ 1127 char *new; 1128 rc = async_string_receive(&new, 0, NULL); 1129 if (rc != EOK) { 1155 1130 free(old); 1156 return; 1157 } 1158 old[olen] = '\0'; 1159 1160 /* Retrieve the new path. */ 1161 if (!async_data_write_receive(&callid, &nlen)) { 1162 ipc_answer_0(callid, EINVAL); 1163 ipc_answer_0(rid, EINVAL); 1164 free(old); 1165 return; 1166 } 1167 char *new = malloc(nlen + 1); 1168 if (!new) { 1169 ipc_answer_0(callid, ENOMEM); 1170 ipc_answer_0(rid, ENOMEM); 1171 free(old); 1172 return; 1173 } 1174 if ((rc = async_data_write_finalize(callid, new, nlen))) { 1175 ipc_answer_0(rid, rc); 1176 free(old); 1177 free(new); 1178 return; 1179 } 1180 new[nlen] = '\0'; 1181 1131 ipc_answer_0(rid, rc); 1132 return; 1133 } 1134 1135 size_t olen; 1136 size_t nlen; 1182 1137 char *oldc = canonify(old, &olen); 1183 1138 char *newc = canonify(new, &nlen); 1184 if (!oldc || !newc) { 1139 1140 if ((!oldc) || (!newc)) { 1185 1141 ipc_answer_0(rid, EINVAL); 1186 1142 free(old); … … 1188 1144 return; 1189 1145 } 1146 1190 1147 oldc[olen] = '\0'; 1191 1148 newc[nlen] = '\0'; 1149 1192 1150 if ((!str_lcmp(newc, oldc, str_length(oldc))) && 1193 1151 ((newc[str_length(oldc)] == '/') || … … 1210 1168 vfs_lookup_res_t new_par_lr; 1211 1169 fibril_rwlock_write_lock(&namespace_rwlock); 1170 1212 1171 /* Lookup the node belonging to the old file name. */ 1213 1172 rc = vfs_lookup_internal(oldc, L_NONE, &old_lr, NULL); … … 1219 1178 return; 1220 1179 } 1180 1221 1181 vfs_node_t *old_node = vfs_node_get(&old_lr); 1222 1182 if (!old_node) { … … 1227 1187 return; 1228 1188 } 1189 1229 1190 /* Determine the path to the parent of the node with the new name. */ 1230 1191 char *parentc = str_dup(newc); … … 1236 1197 return; 1237 1198 } 1199 1238 1200 char *lastsl = str_rchr(parentc + 1, '/'); 1239 1201 if (lastsl) … … 1241 1203 else 1242 1204 parentc[1] = '\0'; 1205 1243 1206 /* Lookup parent of the new file name. */ 1244 1207 rc = vfs_lookup_internal(parentc, L_NONE, &new_par_lr, NULL); … … 1251 1214 return; 1252 1215 } 1216 1253 1217 /* Check whether linking to the same file system instance. */ 1254 1218 if ((old_node->fs_handle != new_par_lr.triplet.fs_handle) || … … 1260 1224 return; 1261 1225 } 1226 1262 1227 /* Destroy the old link for the new name. */ 1263 1228 vfs_node_t *new_node = NULL; 1264 1229 rc = vfs_lookup_internal(newc, L_UNLINK, &new_lr, NULL); 1230 1265 1231 switch (rc) { 1266 1232 case ENOENT: … … 1287 1253 return; 1288 1254 } 1255 1289 1256 /* Create the new link for the new name. */ 1290 1257 rc = vfs_lookup_internal(newc, L_LINK, NULL, NULL, old_node->index); … … 1298 1265 return; 1299 1266 } 1267 1300 1268 fibril_mutex_lock(&nodes_mutex); 1301 1269 old_node->lnkcnt++; 1302 1270 fibril_mutex_unlock(&nodes_mutex); 1271 1303 1272 /* Destroy the link for the old name. */ 1304 1273 rc = vfs_lookup_internal(oldc, L_UNLINK, NULL, NULL); … … 1313 1282 return; 1314 1283 } 1284 1315 1285 fibril_mutex_lock(&nodes_mutex); 1316 1286 old_node->lnkcnt--; … … 1318 1288 fibril_rwlock_write_unlock(&namespace_rwlock); 1319 1289 vfs_node_put(old_node); 1290 1320 1291 if (new_node) 1321 1292 vfs_node_put(new_node); 1293 1322 1294 free(old); 1323 1295 free(new);
Note:
See TracChangeset
for help on using the changeset viewer.