+
+void ___wait_on_page(struct page *page)
+{
+ struct task_struct *tsk = current;
+ DECLARE_WAITQUEUE(wait, tsk);
+
+ add_wait_queue(&page->wait, &wait);
+ do {
+ run_task_queue(&tq_disk);
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+ if (!PageLocked(page))
+ break;
+ schedule();
+ } while (PageLocked(page));
+ tsk->state = TASK_RUNNING;
+ remove_wait_queue(&page->wait, &wait);
+}
+
+void lck_page(struct page *page)
+{
+ while (TryLockPage(page))
+ ___wait_on_page(page);
+}
+
+int gen_copy_data(struct obd_conn *conn, obdattr *src, obdattr *tgt)
+{
+ struct page *page;
+ unsigned long index = 0;
+ int rc;
+
+ page = alloc_page(GFP_USER);
+ if ( !page )
+ return -ENOMEM;
+
+
+ lck_page(page);
+
+ while (index < ((src->i_size + PAGE_SIZE - 1) >> PAGE_SHIFT)) {
+
+ page->index = index;
+ rc = OBP(conn->oc_dev, brw)(READ, conn, src, page, 0);
+
+ if ( rc != PAGE_SIZE )
+ break;
+
+ rc = OBP(conn->oc_dev,brw)(WRITE, conn, tgt, page, 1);
+ if ( rc != PAGE_SIZE)
+ break;
+
+ index ++;
+ }
+ tgt->i_size = src->i_size;
+ tgt->i_blocks = src->i_blocks;
+ UnlockPage(page);
+ __free_page(page);
+
+ return 0;
+}