Index: trunk/kernel/mm/ppm.c
===================================================================
--- trunk/kernel/mm/ppm.c	(revision 585)
+++ trunk/kernel/mm/ppm.c	(revision 606)
@@ -39,4 +39,5 @@
 #include <mapper.h>
 #include <ppm.h>
+#include <vfs.h>
 
 ////////////////////////////////////////////////////////////////////////////////////////
@@ -395,81 +396,187 @@
 //////////////////////////////////////////////////////////////////////////////////////
 
-/////////////////////////////////////////
-bool_t ppm_page_do_dirty( page_t * page )
+//////////////////////////////////////////
+bool_t ppm_page_do_dirty( xptr_t page_xp )
 {
 	bool_t done = false;
 
+    // get page cluster and local pointer
+    page_t * page_ptr = GET_PTR( page_xp );
+    cxy_t    page_cxy = GET_CXY( page_xp );
+
+    // get local pointer on PPM (same in all clusters)
 	ppm_t * ppm = &LOCAL_CLUSTER->ppm;
 
-	// lock the PPM dirty_list
-	queuelock_acquire( &ppm->dirty_lock );
-
-	if( !page_is_flag( page , PG_DIRTY ) )
+    // build extended pointers on page lock, page flags, and PPM dirty list lock
+    xptr_t page_lock_xp  = XPTR( page_cxy , &page_ptr->lock  );    
+    xptr_t page_flags_xp = XPTR( page_cxy , &page_ptr->flags );
+    xptr_t dirty_lock_xp = XPTR( page_cxy , &ppm->dirty_lock );
+           
+	// lock the remote PPM dirty_list
+	remote_queuelock_acquire( dirty_lock_xp );
+
+    // lock the remote page
+    remote_busylock_acquire( page_lock_xp );
+
+    // get remote page flags
+    uint32_t flags = hal_remote_l32( page_flags_xp );
+
+	if( (flags & PG_DIRTY) == 0 )
 	{
 		// set dirty flag in page descriptor
-		page_set_flag( page , PG_DIRTY );
-
-		// register page in PPM dirty list
-		list_add_first( &ppm->dirty_root , &page->list );
+        hal_remote_s32( page_flags_xp , flags | PG_DIRTY );
+
+		// The PPM dirty list is a LOCAL list !!!
+        // We must update 4 pointers to insert a new page in this list.
+        // We can use the standard LIST API when the page is local,
+        // but we cannot use the standard API if the page is remote...
+
+        if( page_cxy == local_cxy )         // locally update the PPM dirty list
+        {
+            list_add_first( &ppm->dirty_root , &page_ptr->list );
+        } 
+        else                                // remotely update the PPM dirty list
+        {
+            // get local and remote pointers on "root" list entry 
+            list_entry_t * root    = &ppm->dirty_root;
+            xptr_t         root_xp = XPTR( page_cxy , root );
+
+            // get local and remote pointers on "page" list entry 
+            list_entry_t * list    = &page_ptr->list;
+            xptr_t         list_xp = XPTR( page_cxy , list );
+
+            // get local and remote pointers on first dirty page 
+            list_entry_t * dirt    = hal_remote_lpt( XPTR( page_cxy, &root->next ) );
+            xptr_t         dirt_xp = XPTR( page_cxy , dirt );
+
+            // set root.next, list.next, list pred, curr.pred in remote cluster
+            hal_remote_spt( root_xp                    , list );
+            hal_remote_spt( list_xp                    , dirt );
+            hal_remote_spt( list_xp + sizeof(intptr_t) , root );
+            hal_remote_spt( dirt_xp + sizeof(intptr_t) , list );
+        }
+
 		done = true;
 	}
 
-	// unlock the PPM dirty_list
-	queuelock_release( &ppm->dirty_lock );
+    // unlock the remote page
+    remote_busylock_release( page_lock_xp );
+
+	// unlock the remote PPM dirty_list
+	remote_queuelock_release( dirty_lock_xp );
 
 	return done;
-}
-
-///////////////////////////////////////////
-bool_t ppm_page_undo_dirty( page_t * page )
+
+} // end ppm_page_do_dirty()
+
+////////////////////////////////////////////
+bool_t ppm_page_undo_dirty( xptr_t page_xp )
 {
 	bool_t done = false;
 
+    // get page cluster and local pointer
+    page_t * page_ptr = GET_PTR( page_xp );
+    cxy_t    page_cxy = GET_CXY( page_xp );
+
+    // get local pointer on PPM (same in all clusters)
 	ppm_t * ppm = &LOCAL_CLUSTER->ppm;
 
-	// lock the dirty_list
-	queuelock_acquire( &ppm->dirty_lock );
-
-	if( page_is_flag( page , PG_DIRTY) )
-	{
-		// clear dirty flag in page descriptor
-		page_clear_flag( page , PG_DIRTY );
-
-		// remove page from PPM dirty list
-		list_unlink( &page->list );
+    // build extended pointers on page lock, page flags, and PPM dirty list lock
+    xptr_t page_lock_xp  = XPTR( page_cxy , &page_ptr->lock  );
+    xptr_t page_flags_xp = XPTR( page_cxy , &page_ptr->flags );
+    xptr_t dirty_lock_xp = XPTR( page_cxy , &ppm->dirty_lock );
+           
+	// lock the remote PPM dirty_list
+	remote_queuelock_acquire( XPTR( page_cxy , &ppm->dirty_lock ) );
+
+    // lock the remote page
+    remote_busylock_acquire( page_lock_xp );
+
+    // get remote page flags
+    uint32_t flags = hal_remote_l32( page_flags_xp );
+
+	if( (flags & PG_DIRTY) )  // page is dirty
+	{
+		// reset dirty flag in page descriptor
+        hal_remote_s32( page_flags_xp , flags & (~PG_DIRTY) );
+
+		// The PPM dirty list is a LOCAL list !!!
+        // We must update 4 pointers to remove a page from this list.
+        // we can use the standard LIST API when the page is local,
+        // but we cannot use the standard API if the page is remote...
+
+        if( page_cxy == local_cxy )         // locally update the PPM dirty list
+        {
+            list_unlink( &page_ptr->list );
+        } 
+        else                                // remotely update the PPM dirty list
+        {
+            // get local and remote pointers on "page" list entry 
+            list_entry_t * list    = &page_ptr->list;
+            xptr_t         list_xp = XPTR( page_cxy , list );
+
+            // get local and remote pointers on "next" page list entry 
+            list_entry_t * next    = hal_remote_lpt( list_xp );
+            xptr_t         next_xp = XPTR( page_cxy , next );
+
+            // get local and remote pointers on "pred" page list entry 
+            list_entry_t * pred    = hal_remote_lpt( list_xp + sizeof(intptr_t) );
+            xptr_t         pred_xp = XPTR( page_cxy , pred );
+
+            // set root.next, list.next, list pred, curr.pred in remote cluster
+            hal_remote_spt( pred_xp                    , next );
+            hal_remote_spt( list_xp                    , NULL );
+            hal_remote_spt( list_xp + sizeof(intptr_t) , NULL );
+            hal_remote_spt( next_xp + sizeof(intptr_t) , pred );
+        }
+
 		done = true;
 	}
 
-	// unlock the dirty_list
-	queuelock_release( &ppm->dirty_lock );
+    // unlock the remote page
+    remote_busylock_release( page_lock_xp );
+
+	// unlock the remote PPM dirty_list
+	remote_queuelock_release( dirty_lock_xp );
 
 	return done;
-}
-
-///////////////////////////////
-void ppm_sync_all_pages( void )
-{
-	page_t   * page;
-	ppm_t    * ppm = &LOCAL_CLUSTER->ppm;
+
+}  // end ppm_page_undo_dirty()
+
+/////////////////////////////////
+void ppm_sync_dirty_pages( void )
+{
+	ppm_t * ppm = &LOCAL_CLUSTER->ppm;
+
+    // get local pointer on PPM dirty_root
+    list_entry_t * dirty_root = &ppm->dirty_root;
+
+    // build extended pointer on PPM dirty_lock 
+    xptr_t dirty_lock_xp = XPTR( local_cxy , &ppm->dirty_lock );
 
 	// get the PPM dirty_list lock
-	queuelock_acquire( &ppm->dirty_lock );
+	remote_queuelock_acquire( dirty_lock_xp );
 
 	while( !list_is_empty( &ppm->dirty_root ) )
 	{
-		page = LIST_FIRST( &ppm->dirty_root ,  page_t , list );
+		page_t * page = LIST_FIRST( dirty_root ,  page_t , list );
+        xptr_t   page_xp = XPTR( local_cxy , page );
+
+        // build extended pointer on page lock
+        xptr_t page_lock_xp = XPTR( local_cxy , &page->lock );
 
 		// get the page lock
-		remote_busylock_acquire( XPTR( local_cxy, &page->lock ) );
+		remote_busylock_acquire( page_lock_xp );
 
 		// sync the page
-		vfs_mapper_move_page( page , false );  // from mapper
+		vfs_fs_move_page( page_xp , false );  // from mapper to device
 
 		// release the page lock
-		remote_busylock_release( XPTR( local_cxy , &page->lock ) );
+		remote_busylock_release( page_lock_xp );
 	}
 
 	// release the PPM dirty_list lock
-	queuelock_release( &ppm->dirty_lock );
-}
-
+	remote_queuelock_release( dirty_lock_xp );
+
+}  // end ppm_sync_dirty_pages()
+
