+
+struct dio_user_copy_data {
+ struct cl_sub_dio *ducd_sdio;
+ struct completion ducd_completion;
+ ssize_t ducd_result;
+};
+
+int ll_dio_user_copy_helper(void *data)
+{
+ struct dio_user_copy_data *ducd = data;
+ struct cl_sub_dio *sdio = ducd->ducd_sdio;
+
+ ducd->ducd_result = __ll_dio_user_copy(sdio);
+ complete(&ducd->ducd_completion);
+
+ return 0;
+}
+
+ssize_t ll_dio_user_copy(struct cl_sub_dio *sdio)
+{
+ struct dio_user_copy_data ducd;
+ struct task_struct *kthread;
+
+ /* normal case - copy is being done by ptlrpcd */
+ if (current->flags & PF_KTHREAD ||
+ /* for non-parallel DIO, the submitting thread does the copy */
+ sdio->csd_ll_aio->cda_mm == current->mm)
+ return __ll_dio_user_copy(sdio);
+
+ /* this is a slightly unfortunate workaround; when doing an fsync, a
+ * user thread may pick up a DIO extent which is about to be written
+ * out. we can't just ignore these, but we also can't handle them from
+ * the user thread, since user threads can't do data copying from
+ * another thread's memory.
+ *
+ * so we spawn a kthread to handle this case.
+ * this will be rare and is not a 'hot path', so the performance
+ * cost doesn't matter
+ */
+ init_completion(&ducd.ducd_completion);
+ ducd.ducd_sdio = sdio;
+
+ kthread = kthread_run(ll_dio_user_copy_helper, &ducd,
+ "ll_ucp_%u", current->pid);
+ if (IS_ERR_OR_NULL(kthread))
+ return PTR_ERR(kthread);
+ wait_for_completion(&ducd.ducd_completion);
+
+ return ducd.ducd_result;
+}