vfs_aio.c (f2e7f06a0de5a6f8f1cdf6e5f4b9b35f193eaa13) | vfs_aio.c (8a4dc40ff46ef766bff63a8328d6dd838547f860) |
---|---|
1/*- 2 * Copyright (c) 1997 John S. Dyson. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. --- 1034 unchanged lines hidden (view full) --- 1043 } 1044 } 1045 if (ki->kaio_flags & KAIO_WAKEUP) { 1046 ki->kaio_flags &= ~KAIO_WAKEUP; 1047 wakeup(&userp->p_aioinfo); 1048 } 1049} 1050 | 1/*- 2 * Copyright (c) 1997 John S. Dyson. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. --- 1034 unchanged lines hidden (view full) --- 1043 } 1044 } 1045 if (ki->kaio_flags & KAIO_WAKEUP) { 1046 ki->kaio_flags &= ~KAIO_WAKEUP; 1047 wakeup(&userp->p_aioinfo); 1048 } 1049} 1050 |
1051static void 1052aio_switch_vmspace(struct aiocblist *aiocbe) 1053{ 1054 1055 vmspace_switch_aio(aiocbe->userproc->p_vmspace); 1056} 1057 |
|
1051/* 1052 * The AIO daemon, most of the actual work is done in aio_process_*, 1053 * but the setup (and address space mgmt) is done in this routine. 1054 */ 1055static void 1056aio_daemon(void *_id) 1057{ 1058 struct aiocblist *aiocbe; 1059 struct aiothreadlist *aiop; 1060 struct kaioinfo *ki; | 1058/* 1059 * The AIO daemon, most of the actual work is done in aio_process_*, 1060 * but the setup (and address space mgmt) is done in this routine. 1061 */ 1062static void 1063aio_daemon(void *_id) 1064{ 1065 struct aiocblist *aiocbe; 1066 struct aiothreadlist *aiop; 1067 struct kaioinfo *ki; |
1061 struct proc *curcp, *mycp, *userp; 1062 struct vmspace *myvm, *tmpvm; | 1068 struct proc *p, *userp; 1069 struct vmspace *myvm; |
1063 struct thread *td = curthread; 1064 int id = (intptr_t)_id; 1065 1066 /* | 1070 struct thread *td = curthread; 1071 int id = (intptr_t)_id; 1072 1073 /* |
1067 * Local copies of curproc (cp) and vmspace (myvm) | 1074 * Grab an extra reference on the daemon's vmspace so that it 1075 * doesn't get freed by jobs that switch to a different 1076 * vmspace. |
1068 */ | 1077 */ |
1069 mycp = td->td_proc; 1070 myvm = mycp->p_vmspace; | 1078 p = td->td_proc; 1079 myvm = vmspace_acquire_ref(p); |
1071 | 1080 |
1072 KASSERT(mycp->p_textvp == NULL, ("kthread has a textvp")); | 1081 KASSERT(p->p_textvp == NULL, ("kthread has a textvp")); |
1073 1074 /* 1075 * Allocate and ready the aio control info. There is one aiop structure 1076 * per daemon. 1077 */ 1078 aiop = uma_zalloc(aiop_zone, M_WAITOK); 1079 aiop->aiothread = td; 1080 aiop->aiothreadflags = 0; 1081 1082 /* 1083 * Wakeup parent process. (Parent sleeps to keep from blasting away 1084 * and creating too many daemons.) 1085 */ 1086 sema_post(&aio_newproc_sem); 1087 1088 mtx_lock(&aio_job_mtx); 1089 for (;;) { 1090 /* | 1082 1083 /* 1084 * Allocate and ready the aio control info. There is one aiop structure 1085 * per daemon. 1086 */ 1087 aiop = uma_zalloc(aiop_zone, M_WAITOK); 1088 aiop->aiothread = td; 1089 aiop->aiothreadflags = 0; 1090 1091 /* 1092 * Wakeup parent process. (Parent sleeps to keep from blasting away 1093 * and creating too many daemons.) 1094 */ 1095 sema_post(&aio_newproc_sem); 1096 1097 mtx_lock(&aio_job_mtx); 1098 for (;;) { 1099 /* |
1091 * curcp is the current daemon process context. 1092 * userp is the current user process context. 1093 */ 1094 curcp = mycp; 1095 1096 /* | |
1097 * Take daemon off of free queue 1098 */ 1099 if (aiop->aiothreadflags & AIOP_FREE) { 1100 TAILQ_REMOVE(&aio_freeproc, aiop, list); 1101 aiop->aiothreadflags &= ~AIOP_FREE; 1102 } 1103 1104 /* 1105 * Check for jobs. 1106 */ 1107 while ((aiocbe = aio_selectjob(aiop)) != NULL) { 1108 mtx_unlock(&aio_job_mtx); 1109 userp = aiocbe->userproc; 1110 1111 /* 1112 * Connect to process address space for user program. 1113 */ | 1100 * Take daemon off of free queue 1101 */ 1102 if (aiop->aiothreadflags & AIOP_FREE) { 1103 TAILQ_REMOVE(&aio_freeproc, aiop, list); 1104 aiop->aiothreadflags &= ~AIOP_FREE; 1105 } 1106 1107 /* 1108 * Check for jobs. 1109 */ 1110 while ((aiocbe = aio_selectjob(aiop)) != NULL) { 1111 mtx_unlock(&aio_job_mtx); 1112 userp = aiocbe->userproc; 1113 1114 /* 1115 * Connect to process address space for user program. 1116 */ |
1114 if (userp != curcp) { 1115 /* 1116 * Save the current address space that we are 1117 * connected to. 1118 */ 1119 tmpvm = mycp->p_vmspace; | 1117 aio_switch_vmspace(aiocbe); |
1120 | 1118 |
1121 /* 1122 * Point to the new user address space, and 1123 * refer to it. 1124 */ 1125 mycp->p_vmspace = userp->p_vmspace; 1126 atomic_add_int(&mycp->p_vmspace->vm_refcnt, 1); 1127 1128 /* Activate the new mapping. */ 1129 pmap_activate(FIRST_THREAD_IN_PROC(mycp)); 1130 1131 /* 1132 * If the old address space wasn't the daemons 1133 * own address space, then we need to remove the 1134 * daemon's reference from the other process 1135 * that it was acting on behalf of. 1136 */ 1137 if (tmpvm != myvm) { 1138 vmspace_free(tmpvm); 1139 } 1140 curcp = userp; 1141 } 1142 | |
1143 ki = userp->p_aioinfo; 1144 1145 /* Do the I/O function. */ 1146 switch(aiocbe->uaiocb.aio_lio_opcode) { 1147 case LIO_READ: 1148 case LIO_WRITE: 1149 aio_process_rw(aiocbe); 1150 break; --- 16 unchanged lines hidden (view full) --- 1167 AIO_UNLOCK(ki); 1168 1169 mtx_lock(&aio_job_mtx); 1170 } 1171 1172 /* 1173 * Disconnect from user address space. 1174 */ | 1119 ki = userp->p_aioinfo; 1120 1121 /* Do the I/O function. */ 1122 switch(aiocbe->uaiocb.aio_lio_opcode) { 1123 case LIO_READ: 1124 case LIO_WRITE: 1125 aio_process_rw(aiocbe); 1126 break; --- 16 unchanged lines hidden (view full) --- 1143 AIO_UNLOCK(ki); 1144 1145 mtx_lock(&aio_job_mtx); 1146 } 1147 1148 /* 1149 * Disconnect from user address space. 1150 */ |
1175 if (curcp != mycp) { 1176 | 1151 if (p->p_vmspace != myvm) { |
1177 mtx_unlock(&aio_job_mtx); | 1152 mtx_unlock(&aio_job_mtx); |
1178 1179 /* Get the user address space to disconnect from. */ 1180 tmpvm = mycp->p_vmspace; 1181 1182 /* Get original address space for daemon. */ 1183 mycp->p_vmspace = myvm; 1184 1185 /* Activate the daemon's address space. */ 1186 pmap_activate(FIRST_THREAD_IN_PROC(mycp)); 1187#ifdef DIAGNOSTIC 1188 if (tmpvm == myvm) { 1189 printf("AIOD: vmspace problem -- %d\n", 1190 mycp->p_pid); 1191 } 1192#endif 1193 /* Remove our vmspace reference. */ 1194 vmspace_free(tmpvm); 1195 1196 curcp = mycp; 1197 | 1153 vmspace_switch_aio(myvm); |
1198 mtx_lock(&aio_job_mtx); 1199 /* 1200 * We have to restart to avoid race, we only sleep if | 1154 mtx_lock(&aio_job_mtx); 1155 /* 1156 * We have to restart to avoid race, we only sleep if |
1201 * no job can be selected, that should be 1202 * curcp == mycp. | 1157 * no job can be selected. |
1203 */ 1204 continue; 1205 } 1206 1207 mtx_assert(&aio_job_mtx, MA_OWNED); 1208 1209 TAILQ_INSERT_HEAD(&aio_freeproc, aiop, list); 1210 aiop->aiothreadflags |= AIOP_FREE; 1211 1212 /* 1213 * If daemon is inactive for a long time, allow it to exit, 1214 * thereby freeing resources. 1215 */ 1216 if (msleep(aiop->aiothread, &aio_job_mtx, PRIBIO, "aiordy", | 1158 */ 1159 continue; 1160 } 1161 1162 mtx_assert(&aio_job_mtx, MA_OWNED); 1163 1164 TAILQ_INSERT_HEAD(&aio_freeproc, aiop, list); 1165 aiop->aiothreadflags |= AIOP_FREE; 1166 1167 /* 1168 * If daemon is inactive for a long time, allow it to exit, 1169 * thereby freeing resources. 1170 */ 1171 if (msleep(aiop->aiothread, &aio_job_mtx, PRIBIO, "aiordy", |
1217 aiod_lifetime)) { 1218 if (TAILQ_EMPTY(&aio_jobs)) { 1219 if ((aiop->aiothreadflags & AIOP_FREE) && 1220 (num_aio_procs > target_aio_procs)) { 1221 TAILQ_REMOVE(&aio_freeproc, aiop, list); 1222 num_aio_procs--; 1223 mtx_unlock(&aio_job_mtx); 1224 uma_zfree(aiop_zone, aiop); 1225 free_unr(aiod_unr, id); 1226#ifdef DIAGNOSTIC 1227 if (mycp->p_vmspace->vm_refcnt <= 1) { 1228 printf("AIOD: bad vm refcnt for" 1229 " exiting daemon: %d\n", 1230 mycp->p_vmspace->vm_refcnt); 1231 } 1232#endif 1233 kproc_exit(0); 1234 } 1235 } 1236 } | 1172 aiod_lifetime) == EWOULDBLOCK && TAILQ_EMPTY(&aio_jobs) && 1173 (aiop->aiothreadflags & AIOP_FREE) && 1174 num_aio_procs > target_aio_procs) 1175 break; |
1237 } | 1176 } |
1177 TAILQ_REMOVE(&aio_freeproc, aiop, list); 1178 num_aio_procs--; |
|
1238 mtx_unlock(&aio_job_mtx); | 1179 mtx_unlock(&aio_job_mtx); |
1239 panic("shouldn't be here\n"); | 1180 uma_zfree(aiop_zone, aiop); 1181 free_unr(aiod_unr, id); 1182 vmspace_free(myvm); 1183 1184 KASSERT(p->p_vmspace == myvm, 1185 ("AIOD: bad vmspace for exiting daemon")); 1186 KASSERT(myvm->vm_refcnt > 1, 1187 ("AIOD: bad vm refcnt for exiting daemon: %d", myvm->vm_refcnt)); 1188 kproc_exit(0); |
1240} 1241 1242/* 1243 * Create a new AIO daemon. This is mostly a kernel-thread fork routine. The 1244 * AIO daemon modifies its environment itself. 1245 */ 1246static int 1247aio_newproc(int *start) --- 1822 unchanged lines hidden --- | 1189} 1190 1191/* 1192 * Create a new AIO daemon. This is mostly a kernel-thread fork routine. The 1193 * AIO daemon modifies its environment itself. 1194 */ 1195static int 1196aio_newproc(int *start) --- 1822 unchanged lines hidden --- |