Changeset 62da45a in mainline
- Timestamp:
- 2008-01-18T18:02:24Z (17 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 5973fd0
- Parents:
- 4cc2ddd
- Location:
- uspace/srv/vfs
- Files:
-
- 2 added
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/vfs/Makefile
r4cc2ddd r62da45a 1 1 # 2 2 # Copyright (c) 2006 Martin Decky 3 # Copyright (c) 200 7Jakub Jermar3 # Copyright (c) 2008 Jakub Jermar 4 4 # All rights reserved. 5 5 # … … 45 45 vfs_node.c \ 46 46 vfs_file.c \ 47 vfs_ops.c 47 vfs_ops.c \ 48 vfs_lookup.c \ 49 vfs_register.c 48 50 49 51 OBJECTS := $(addsuffix .o,$(basename $(SOURCES))) -
uspace/srv/vfs/vfs_ops.c
r4cc2ddd r62da45a 37 37 38 38 #include <ipc/ipc.h> 39 #include <ipc/services.h>40 39 #include <async.h> 41 #include <fibril.h>42 40 #include <errno.h> 43 41 #include <stdio.h> … … 50 48 #include <unistd.h> 51 49 #include <ctype.h> 52 #include <as.h>53 50 #include <assert.h> 54 51 #include <atomic.h> 55 52 #include "vfs.h" 56 57 #define min(a, b) ((a) < (b) ? (a) : (b))58 53 59 54 /** … … 62 57 */ 63 58 RWLOCK_INITIALIZE(namespace_rwlock); 64 65 atomic_t plb_futex = FUTEX_INITIALIZER;66 link_t plb_head; /**< PLB entry ring buffer. */67 uint8_t *plb = NULL;68 69 /** Perform a path lookup.70 *71 * @param path Path to be resolved; it needn't be an ASCIIZ string.72 * @param len Number of path characters pointed by path.73 * @param result Empty structure where the lookup result will be stored.74 * @param altroot If non-empty, will be used instead of rootfs as the root75 * of the whole VFS tree.76 *77 * @return EOK on success or an error code from errno.h.78 */79 int vfs_lookup_internal(char *path, size_t len, vfs_lookup_res_t *result,80 vfs_pair_t *altroot)81 {82 vfs_pair_t *root;83 84 if (!len)85 return EINVAL;86 87 if (altroot)88 root = altroot;89 else90 root = (vfs_pair_t *) &rootfs;91 92 if (!root->fs_handle)93 return ENOENT;94 95 futex_down(&plb_futex);96 97 plb_entry_t entry;98 link_initialize(&entry.plb_link);99 entry.len = len;100 101 off_t first; /* the first free index */102 off_t last; /* the last free index */103 104 if (list_empty(&plb_head)) {105 first = 0;106 last = PLB_SIZE - 1;107 } else {108 plb_entry_t *oldest = list_get_instance(plb_head.next,109 plb_entry_t, plb_link);110 plb_entry_t *newest = list_get_instance(plb_head.prev,111 plb_entry_t, plb_link);112 113 first = (newest->index + newest->len) % PLB_SIZE;114 last = (oldest->index - 1) % PLB_SIZE;115 }116 117 if (first <= last) {118 if ((last - first) + 1 < len) {119 /*120 * The buffer cannot absorb the path.121 */122 futex_up(&plb_futex);123 return ELIMIT;124 }125 } else {126 if (PLB_SIZE - ((first - last) + 1) < len) {127 /*128 * The buffer cannot absorb the path.129 */130 futex_up(&plb_futex);131 return ELIMIT;132 }133 }134 135 /*136 * We know the first free index in PLB and we also know that there is137 * enough space in the buffer to hold our path.138 */139 140 entry.index = first;141 entry.len = len;142 143 /*144 * Claim PLB space by inserting the entry into the PLB entry ring145 * buffer.146 */147 list_append(&entry.plb_link, &plb_head);148 149 futex_up(&plb_futex);150 151 /*152 * Copy the path into PLB.153 */154 size_t cnt1 = min(len, (PLB_SIZE - first) + 1);155 size_t cnt2 = len - cnt1;156 157 memcpy(&plb[first], path, cnt1);158 memcpy(plb, &path[cnt1], cnt2);159 160 ipc_call_t answer;161 int phone = vfs_grab_phone(root->fs_handle);162 aid_t req = async_send_3(phone, VFS_LOOKUP, (ipcarg_t) first,163 (ipcarg_t) (first + len - 1) % PLB_SIZE,164 (ipcarg_t) root->dev_handle, &answer);165 vfs_release_phone(phone);166 167 ipcarg_t rc;168 async_wait_for(req, &rc);169 170 futex_down(&plb_futex);171 list_remove(&entry.plb_link);172 /*173 * Erasing the path from PLB will come handy for debugging purposes.174 */175 memset(&plb[first], 0, cnt1);176 memset(plb, 0, cnt2);177 futex_up(&plb_futex);178 179 if (rc == EOK) {180 result->triplet.fs_handle = (int) IPC_GET_ARG1(answer);181 result->triplet.dev_handle = (int) IPC_GET_ARG2(answer);182 result->triplet.index = (int) IPC_GET_ARG3(answer);183 result->size = (size_t) IPC_GET_ARG4(answer);184 }185 186 return rc;187 }188 59 189 60 atomic_t rootfs_futex = FUTEX_INITIALIZER; … … 713 584 714 585 futex_up(&file->lock); 715 716 return rc; 717 } 718 719 atomic_t fs_head_futex = FUTEX_INITIALIZER; 720 link_t fs_head; 721 722 atomic_t fs_handle_next = { 723 .count = 1 724 }; 725 726 /** Verify the VFS info structure. 727 * 728 * @param info Info structure to be verified. 729 * 730 * @return Non-zero if the info structure is sane, zero otherwise. 731 */ 732 static bool vfs_info_sane(vfs_info_t *info) 733 { 734 int i; 735 736 /* 737 * Check if the name is non-empty and is composed solely of ASCII 738 * characters [a-z]+[a-z0-9_-]*. 739 */ 740 if (!islower(info->name[0])) { 741 dprintf("The name doesn't start with a lowercase character.\n"); 742 return false; 743 } 744 for (i = 1; i < FS_NAME_MAXLEN; i++) { 745 if (!(islower(info->name[i]) || isdigit(info->name[i])) && 746 (info->name[i] != '-') && (info->name[i] != '_')) { 747 if (info->name[i] == '\0') { 748 break; 749 } else { 750 dprintf("The name contains illegal " 751 "characters.\n"); 752 return false; 753 } 754 } 755 } 756 /* 757 * This check is not redundant. It ensures that the name is 758 * NULL-terminated, even if FS_NAME_MAXLEN characters are used. 759 */ 760 if (info->name[i] != '\0') { 761 dprintf("The name is not properly NULL-terminated.\n"); 762 return false; 763 } 764 765 766 /* 767 * Check if the FS implements mandatory VFS operations. 768 */ 769 if (info->ops[IPC_METHOD_TO_VFS_OP(VFS_LOOKUP)] != VFS_OP_DEFINED) { 770 dprintf("Operation VFS_LOOKUP not defined by the client.\n"); 771 return false; 772 } 773 if (info->ops[IPC_METHOD_TO_VFS_OP(VFS_OPEN)] != VFS_OP_DEFINED) { 774 dprintf("Operation VFS_OPEN not defined by the client.\n"); 775 return false; 776 } 777 if (info->ops[IPC_METHOD_TO_VFS_OP(VFS_CLOSE)] != VFS_OP_DEFINED) { 778 dprintf("Operation VFS_CLOSE not defined by the client.\n"); 779 return false; 780 } 781 if (info->ops[IPC_METHOD_TO_VFS_OP(VFS_READ)] != VFS_OP_DEFINED) { 782 dprintf("Operation VFS_READ not defined by the client.\n"); 783 return false; 784 } 785 786 /* 787 * Check if each operation is either not defined, defined or default. 788 */ 789 for (i = VFS_FIRST; i < VFS_LAST_CLNT; i++) { 790 if ((info->ops[IPC_METHOD_TO_VFS_OP(i)] != VFS_OP_NULL) && 791 (info->ops[IPC_METHOD_TO_VFS_OP(i)] != VFS_OP_DEFAULT) && 792 (info->ops[IPC_METHOD_TO_VFS_OP(i)] != VFS_OP_DEFINED)) { 793 dprintf("Operation info not understood.\n"); 794 return false; 795 } 796 } 797 return true; 798 } 799 800 /** VFS_REGISTER protocol function. 801 * 802 * @param rid Hash of the call with the request. 803 * @param request Call structure with the request. 804 */ 805 void vfs_register(ipc_callid_t rid, ipc_call_t *request) 806 { 807 ipc_callid_t callid; 808 ipc_call_t call; 809 int rc; 810 size_t size; 811 812 dprintf("Processing VFS_REGISTER request received from %p.\n", 813 request->in_phone_hash); 814 815 /* 816 * The first call has to be IPC_M_DATA_SEND in which we receive the 817 * VFS info structure from the client FS. 818 */ 819 if (!ipc_data_write_receive(&callid, &size)) { 820 /* 821 * The client doesn't obey the same protocol as we do. 822 */ 823 dprintf("Receiving of VFS info failed.\n"); 824 ipc_answer_0(callid, EINVAL); 825 ipc_answer_0(rid, EINVAL); 826 return; 827 } 828 829 dprintf("VFS info received, size = %d\n", size); 830 831 /* 832 * We know the size of the VFS info structure. See if the client 833 * understands this easy concept too. 834 */ 835 if (size != sizeof(vfs_info_t)) { 836 /* 837 * The client is sending us something, which cannot be 838 * the info structure. 839 */ 840 dprintf("Received VFS info has bad size.\n"); 841 ipc_answer_0(callid, EINVAL); 842 ipc_answer_0(rid, EINVAL); 843 return; 844 } 845 846 /* 847 * Allocate and initialize a buffer for the fs_info structure. 848 */ 849 fs_info_t *fs_info; 850 fs_info = (fs_info_t *) malloc(sizeof(fs_info_t)); 851 if (!fs_info) { 852 dprintf("Could not allocate memory for FS info.\n"); 853 ipc_answer_0(callid, ENOMEM); 854 ipc_answer_0(rid, ENOMEM); 855 return; 856 } 857 link_initialize(&fs_info->fs_link); 858 futex_initialize(&fs_info->phone_futex, 1); 859 860 rc = ipc_data_write_finalize(callid, &fs_info->vfs_info, size); 861 if (rc != EOK) { 862 dprintf("Failed to deliver the VFS info into our AS, rc=%d.\n", 863 rc); 864 free(fs_info); 865 ipc_answer_0(callid, rc); 866 ipc_answer_0(rid, rc); 867 return; 868 } 869 870 dprintf("VFS info delivered.\n"); 871 872 if (!vfs_info_sane(&fs_info->vfs_info)) { 873 free(fs_info); 874 ipc_answer_0(callid, EINVAL); 875 ipc_answer_0(rid, EINVAL); 876 return; 877 } 878 879 futex_down(&fs_head_futex); 880 881 /* 882 * Check for duplicit registrations. 883 */ 884 if (fs_name_to_handle(fs_info->vfs_info.name, false)) { 885 /* 886 * We already register a fs like this. 887 */ 888 dprintf("FS is already registered.\n"); 889 futex_up(&fs_head_futex); 890 free(fs_info); 891 ipc_answer_0(callid, EEXISTS); 892 ipc_answer_0(rid, EEXISTS); 893 return; 894 } 895 896 /* 897 * Add fs_info to the list of registered FS's. 898 */ 899 dprintf("Inserting FS into the list of registered file systems.\n"); 900 list_append(&fs_info->fs_link, &fs_head); 901 902 /* 903 * Now we want the client to send us the IPC_M_CONNECT_TO_ME call so 904 * that a callback connection is created and we have a phone through 905 * which to forward VFS requests to it. 906 */ 907 callid = async_get_call(&call); 908 if (IPC_GET_METHOD(call) != IPC_M_CONNECT_TO_ME) { 909 dprintf("Unexpected call, method = %d\n", IPC_GET_METHOD(call)); 910 list_remove(&fs_info->fs_link); 911 futex_up(&fs_head_futex); 912 free(fs_info); 913 ipc_answer_0(callid, EINVAL); 914 ipc_answer_0(rid, EINVAL); 915 return; 916 } 917 fs_info->phone = IPC_GET_ARG5(call); 918 ipc_answer_0(callid, EOK); 919 920 dprintf("Callback connection to FS created.\n"); 921 922 /* 923 * The client will want us to send him the address space area with PLB. 924 */ 925 926 if (!ipc_share_in_receive(&callid, &size)) { 927 dprintf("Unexpected call, method = %d\n", IPC_GET_METHOD(call)); 928 list_remove(&fs_info->fs_link); 929 futex_up(&fs_head_futex); 930 ipc_hangup(fs_info->phone); 931 free(fs_info); 932 ipc_answer_0(callid, EINVAL); 933 ipc_answer_0(rid, EINVAL); 934 return; 935 } 936 937 /* 938 * We can only send the client address space area PLB_SIZE bytes long. 939 */ 940 if (size != PLB_SIZE) { 941 dprintf("Client suggests wrong size of PFB, size = %d\n", size); 942 list_remove(&fs_info->fs_link); 943 futex_up(&fs_head_futex); 944 ipc_hangup(fs_info->phone); 945 free(fs_info); 946 ipc_answer_0(callid, EINVAL); 947 ipc_answer_0(rid, EINVAL); 948 return; 949 } 950 951 /* 952 * Commit to read-only sharing the PLB with the client. 953 */ 954 (void) ipc_share_in_finalize(callid, plb, 955 AS_AREA_READ | AS_AREA_CACHEABLE); 956 957 dprintf("Sharing PLB.\n"); 958 959 /* 960 * That was it. The FS has been registered. 961 * In reply to the VFS_REGISTER request, we assign the client file 962 * system a global file system handle. 963 */ 964 fs_info->fs_handle = (int) atomic_postinc(&fs_handle_next); 965 ipc_answer_1(rid, EOK, (ipcarg_t) fs_info->fs_handle); 966 967 futex_up(&fs_head_futex); 968 969 dprintf("\"%.*s\" filesystem successfully registered, handle=%d.\n", 970 FS_NAME_MAXLEN, fs_info->vfs_info.name, fs_info->fs_handle); 971 } 972 973 /** For a given file system handle, implement policy for allocating a phone. 974 * 975 * @param handle File system handle. 976 * 977 * @return Phone over which a multi-call request can be safely 978 * sent. Return 0 if no phone was found. 979 */ 980 int vfs_grab_phone(int handle) 981 { 982 /* 983 * For now, we don't try to be very clever and very fast. 984 * We simply lookup the phone in the fs_head list. We currently don't 985 * open any additional phones (even though that itself would be pretty 986 * straightforward; housekeeping multiple open phones to a FS task would 987 * be more demanding). Instead, we simply take the respective 988 * phone_futex and keep it until vfs_release_phone(). 989 */ 990 futex_down(&fs_head_futex); 991 link_t *cur; 992 fs_info_t *fs; 993 for (cur = fs_head.next; cur != &fs_head; cur = cur->next) { 994 fs = list_get_instance(cur, fs_info_t, fs_link); 995 if (fs->fs_handle == handle) { 996 futex_up(&fs_head_futex); 997 /* 998 * For now, take the futex unconditionally. 999 * Oh yeah, serialization rocks. 1000 * It will be up'ed in vfs_release_phone(). 1001 */ 1002 futex_down(&fs->phone_futex); 1003 /* 1004 * Avoid deadlock with other fibrils in the same thread 1005 * by disabling fibril preemption. 1006 */ 1007 fibril_inc_sercount(); 1008 return fs->phone; 1009 } 1010 } 1011 futex_up(&fs_head_futex); 1012 return 0; 1013 } 1014 1015 /** Tell VFS that the phone is in use for any request. 1016 * 1017 * @param phone Phone to FS task. 1018 */ 1019 void vfs_release_phone(int phone) 1020 { 1021 bool found = false; 1022 1023 /* 1024 * Undo the fibril_inc_sercount() done in vfs_grab_phone(). 1025 */ 1026 fibril_dec_sercount(); 1027 1028 futex_down(&fs_head_futex); 1029 link_t *cur; 1030 for (cur = fs_head.next; cur != &fs_head; cur = cur->next) { 1031 fs_info_t *fs = list_get_instance(cur, fs_info_t, fs_link); 1032 if (fs->phone == phone) { 1033 found = true; 1034 futex_up(&fs_head_futex); 1035 futex_up(&fs->phone_futex); 1036 return; 1037 } 1038 } 1039 futex_up(&fs_head_futex); 1040 1041 /* 1042 * Not good to get here. 1043 */ 1044 assert(found == true); 1045 } 1046 1047 /** Convert file system name to its handle. 1048 * 1049 * @param name File system name. 1050 * @param lock If true, the function will down and up the 1051 * fs_head_futex. 1052 * 1053 * @return File system handle or zero if file system not found. 1054 */ 1055 int fs_name_to_handle(char *name, bool lock) 1056 { 1057 int handle = 0; 1058 1059 if (lock) 1060 futex_down(&fs_head_futex); 1061 link_t *cur; 1062 for (cur = fs_head.next; cur != &fs_head; cur = cur->next) { 1063 fs_info_t *fs = list_get_instance(cur, fs_info_t, fs_link); 1064 if (strncmp(fs->vfs_info.name, name, 1065 sizeof(fs->vfs_info.name)) == 0) { 1066 handle = fs->fs_handle; 1067 break; 1068 } 1069 } 1070 if (lock) 1071 futex_up(&fs_head_futex); 1072 return handle; 586 ipc_answer_0(rid, rc); 1073 587 } 1074 588
Note:
See TracChangeset
for help on using the changeset viewer.