- Timestamp:
- Mar 29, 2019 3:17:48 AM (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/linux/sharedfolders/regops.c
r77943 r77944 124 124 * Internal Functions * 125 125 *********************************************************************************************************************************/ 126 DECLINLINE(void) vbsf_put_page(struct page *pPage); 126 127 DECLINLINE(void) vbsf_unlock_user_pages(struct page **papPages, size_t cPages, bool fSetDirty, bool fLockPgHack); 127 128 static void vbsf_reg_write_sync_page_cache(struct address_space *mapping, loff_t offFile, uint32_t cbRange, … … 1013 1014 1014 1015 #endif /* 2.6.17 <= LINUX_VERSION_CODE < 3.16.0 */ 1016 1017 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 30) \ 1018 && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) 1019 /** 1020 * Our own senfile implementation that does not go via the page cache like 1021 * generic_file_sendfile() does. 1022 */ 1023 static ssize_t vbsf_reg_sendfile(struct file *pFile, loff_t *poffFile, size_t cbToSend, read_actor_t pfnActor, void *pvUser) 1024 { 1025 struct inode *inode = VBSF_GET_F_DENTRY(pFile)->d_inode; 1026 struct vbsf_super_info *sf_g = VBSF_GET_SUPER_INFO(inode->i_sb); 1027 ssize_t cbRet; 1028 SFLOGFLOW(("vbsf_reg_sendfile: pFile=%p poffFile=%p{%#RX64} cbToSend=%#zx pfnActor=%p pvUser=%p\n", 1029 pFile, poffFile, poffFile ? *poffFile : 0, cbToSend, pfnActor, pvUser)); 1030 Assert(sf_g); 1031 1032 /* 1033 * Return immediately if asked to send nothing. 1034 */ 1035 if (cbToSend == 0) 1036 return 0; 1037 1038 /* 1039 * Like for vbsf_reg_read() and vbsf_reg_read_iter(), we allow going via 1040 * the page cache in some cases or configs. 1041 */ 1042 if (vbsf_should_use_cached_read(pFile, inode->i_mapping, sf_g)) { 1043 cbRet = generic_file_sendfile(pFile, poffFile, cbToSend, pfnActor, pvUser); 1044 SFLOGFLOW(("vbsf_reg_sendfile: returns %#zx *poffFile=%#RX64 [generic_file_sendfile]\n", cbRet, poffFile ? *poffFile : UINT64_MAX)); 1045 } else { 1046 /* 1047 * Allocate a request and a bunch of pages for reading from the file. 1048 */ 1049 struct page *apPages[16]; 1050 loff_t offFile = poffFile ? *poffFile : 0; 1051 size_t const cPages = cbToSend + ((size_t)offFile & PAGE_OFFSET_MASK) >= RT_ELEMENTS(apPages) * PAGE_SIZE 1052 ? RT_ELEMENTS(apPages) 1053 : RT_ALIGN_Z(cbToSend + ((size_t)offFile & PAGE_OFFSET_MASK), PAGE_SIZE) >> PAGE_SHIFT; 1054 size_t iPage; 1055 VBOXSFREADPGLSTREQ *pReq = (VBOXSFREADPGLSTREQ *)VbglR0PhysHeapAlloc(RT_UOFFSETOF_DYN(VBOXSFREADPGLSTREQ, 1056 PgLst.aPages[cPages])); 1057 if (pReq) { 1058 Assert(cPages > 0); 1059 cbRet = 0; 1060 for (iPage = 0; iPage < cPages; iPage++) { 1061 struct page *pPage; 1062 apPages[iPage] = pPage = alloc_page(GFP_USER); 1063 if (pPage) { 1064 Assert(page_count(pPage) == 1); 1065 pReq->PgLst.aPages[iPage] = page_to_phys(pPage); 1066 } else { 1067 while (iPage-- > 0) 1068 vbsf_put_page(apPages[iPage]); 1069 cbRet = -ENOMEM; 1070 break; 1071 } 1072 } 1073 if (cbRet == 0) { 1074 /* 1075 * Do the job. 1076 */ 1077 struct vbsf_reg_info *sf_r = (struct vbsf_reg_info *)pFile->private_data; 1078 read_descriptor_t RdDesc; 1079 RdDesc.count = cbToSend; 1080 RdDesc.arg.data = pvUser; 1081 RdDesc.written = 0; 1082 RdDesc.error = 0; 1083 1084 Assert(sf_r); 1085 Assert((sf_r->Handle.fFlags & VBSF_HANDLE_F_MAGIC_MASK) == VBSF_HANDLE_F_MAGIC); 1086 1087 while (cbToSend > 0) { 1088 /* 1089 * Read another chunk. For paranoid reasons, we keep data where the page cache 1090 * would keep it, i.e. page offset bits corresponds to the file offset bits. 1091 */ 1092 uint32_t const offPg0 = (uint32_t)offFile & (uint32_t)PAGE_OFFSET_MASK; 1093 uint32_t const cbToRead = RT_MIN((cPages << PAGE_SHIFT) - offPg0, cbToSend); 1094 uint32_t const cPagesToRead = RT_ALIGN_Z(cbToRead + offPg0, PAGE_SIZE) >> PAGE_SHIFT; 1095 int vrc; 1096 pReq->PgLst.offFirstPage = (uint16_t)offPg0; 1097 if (!signal_pending(current)) 1098 vrc = VbglR0SfHostReqReadPgLst(sf_g->map.root, pReq, sf_r->Handle.hHost, offFile, cbToRead, cPagesToRead); 1099 else 1100 vrc = VERR_INTERRUPTED; 1101 if (RT_SUCCESS(vrc)) { 1102 /* 1103 * Pass what we read to the actor. 1104 */ 1105 uint32_t off = offPg0; 1106 uint32_t cbActual = pReq->Parms.cb32Read.u.value32; 1107 bool const fIsEof = cbActual < cbToRead; 1108 AssertStmt(cbActual <= cbToRead, cbActual = cbToRead); 1109 SFLOG3(("vbsf_reg_sendfile: Read %#x bytes (offPg0=%#x), wanted %#x ...\n", cbActual, offPg0, cbToRead)); 1110 1111 iPage = 0; 1112 while (cbActual > 0) { 1113 uint32_t const cbPage = RT_MIN(cbActual, PAGE_SIZE - off); 1114 int const cbRetActor = pfnActor(&RdDesc, apPages[iPage], off, cbPage); 1115 Assert(cbRetActor >= 0); /* Returns zero on failure, with RdDesc.error holding the status code. */ 1116 1117 AssertMsg(iPage < cPages && iPage < cPagesToRead, ("iPage=%#x cPages=%#x cPagesToRead=%#x\n", iPage, cPages, cPagesToRead)); 1118 1119 offFile += cbRetActor; 1120 if ((uint32_t)cbRetActor == cbPage && RdDesc.count > 0) { 1121 cbActual -= cbPage; 1122 cbToSend -= cbPage; 1123 iPage++; 1124 } else { 1125 SFLOG3(("vbsf_reg_sendfile: cbRetActor=%#x (%d) cbPage=%#x RdDesc{count=%#lx error=%d} iPage=%#x/%#x/%#x cbToSend=%#zx\n", 1126 cbRetActor, cbRetActor, cbPage, RdDesc.count, RdDesc.error, iPage, cPagesToRead, cPages, cbToSend)); 1127 vrc = VERR_CALLBACK_RETURN; 1128 break; 1129 } 1130 off = 0; 1131 } 1132 1133 /* 1134 * Are we done yet? 1135 */ 1136 if (RT_FAILURE_NP(vrc) || cbToSend == 0 || RdDesc.error != 0 || fIsEof) { 1137 break; 1138 } 1139 1140 /* 1141 * Replace pages held by the actor. 1142 */ 1143 vrc = VINF_SUCCESS; 1144 for (iPage = 0; iPage < cPages; iPage++) { 1145 struct page *pPage = apPages[iPage]; 1146 if (page_count(pPage) != 1) { 1147 struct page *pNewPage = alloc_page(GFP_USER); 1148 if (pNewPage) { 1149 SFLOGFLOW(("vbsf_reg_sendfile: Replacing page #%x: %p -> %p\n", iPage, pPage, pNewPage)); 1150 vbsf_put_page(pPage); 1151 apPages[iPage] = pNewPage; 1152 } else { 1153 SFLOGFLOW(("vbsf_reg_sendfile: Failed to allocate a replacement page.\n")); 1154 vrc = VERR_NO_MEMORY; 1155 break; 1156 } 1157 } 1158 } 1159 if (RT_FAILURE(vrc)) 1160 break; /* RdDesc.written should be non-zero, so don't bother with setting error. */ 1161 } else { 1162 RdDesc.error = vrc == VERR_INTERRUPTED ? -ERESTARTSYS : -RTErrConvertToErrno(vrc); 1163 SFLOGFLOW(("vbsf_reg_sendfile: Read failed: %Rrc -> %zd (RdDesc.error=%#d)\n", 1164 vrc, -RTErrConvertToErrno(vrc), RdDesc.error)); 1165 break; 1166 } 1167 } 1168 1169 /* 1170 * Free memory. 1171 */ 1172 for (iPage = 0; iPage < cPages; iPage++) 1173 vbsf_put_page(apPages[iPage]); 1174 1175 /* 1176 * Set the return values. 1177 */ 1178 if (RdDesc.written) { 1179 cbRet = RdDesc.written; 1180 if (poffFile) 1181 *poffFile = offFile; 1182 } else { 1183 cbRet = RdDesc.error; 1184 } 1185 } 1186 VbglR0PhysHeapFree(pReq); 1187 } else { 1188 cbRet = -ENOMEM; 1189 } 1190 SFLOGFLOW(("vbsf_reg_sendfile: returns %#zx offFile=%#RX64\n", cbRet, offFile)); 1191 } 1192 return cbRet; 1193 } 1194 #endif /* 2.5.30 <= LINUX_VERSION_CODE < 2.6.23 */ 1015 1195 1016 1196 … … 3192 3372 #endif 3193 3373 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) 3194 .sendfile = generic_file_sendfile, /**< @todo this goes thru page cache. */3374 .sendfile = vbsf_reg_sendfile, 3195 3375 #endif 3196 3376 .llseek = vbsf_reg_llseek,
Note:
See TracChangeset
for help on using the changeset viewer.