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 ---