Understanding Logical Pages (lpages) in OS/161
Overview
Logical pages (lpages) represent virtual pages in OS/161's VM system. Each lpage tracks both the physical-memory state (if the page is in RAM) and swap state (if the page is on disk) for a single virtual page. When implementing VM operations that manipulate pages, you'll need to understand how to properly create, manage, and destroy lpages.
Key Data Structure
struct lpage {
volatile paddr_t lp_paddr; /* physical addr (& flags in low bits) */
off_t lp_swapaddr; /* location in swap file */
struct spinlock lp_spinlock; /* synchronization */
}
Important aspects:
lp_paddr: Physical address where page resides (if in memory)- Low bits used for flags (like dirty state)
INVALID_PADDRif page is not in memory
lp_swapaddr: Where page is stored in swapINVALID_SWAPADDRif no swap allocated
- Protected by its own spinlock for thread safety
The macro LP_ISDIRTY(lp) checks whether the page is dirty (modified). The LP_SET and LP_CLEAR macros can be used to set or clear flags in the lp_paddr field (e.g., LP_SET(lp, LPF_DIRTY)).
struct lpage_array is a dynamic array of lpage structures, used to manage multiple pages together. It follows the interface described in array.h:
lpage_array_create— allocate an array oflpageslpage_array_destroy— destroy an allocated arraylpage_array_init— initialize an array in externally allocated spacelpage_array_cleanup— clean up an array in externally allocated spacelpage_array_num— return number of elements in arraylpage_array_get— return element at indexINDEXlpage_array_set— set element at indexINDEXtoVALlpage_array_preallocate— allocate space without changing sizelpage_array_setsize— change size toNUMelementslpage_array_add— appendVALto end of arraylpage_array_remove— remove entry at indexINDEXand slide subsequent entries down
Key Functions for VM Operations
Creation and Destruction
/* Create a new lpage structure */
struct lpage *lpage_create(void);
/* Destroy an lpage and free its resources */
void lpage_destroy(struct lpage *lp);
Important notes:
lpage_createallocates the structure but doesn't allocate physical memorylpage_destroyhandles both memory and swap cleanup- Always check return value of
lpage_create(might return NULL)
Page-State Management
/* Lock an lpage for exclusive access */
void lpage_lock(struct lpage *lp);
/* Release the lock */
void lpage_unlock(struct lpage *lp);
/* Lock the lpage and pin its physical page (if any) */
void lpage_lock_and_pin(struct lpage *lp);
Special Operations
/* Create a zero-filled page */
int lpage_zerofill(struct lpage **lpret);
/* Copy contents from one page to another */
int lpage_copy(struct lpage *from, struct lpage **toret);
Both of these functions use the internal helper lpage_materialize to create a new page and allocate swap and RAM for it. It doesn't initialize the page contents, but returns the page locked and the physical page pinned ready to be initialized by the caller.
Handling Faults and Evictions
/* Handle a page fault */
int lpage_fault(struct lpage *lp, struct addrspace *,
int faulttype, vaddr_t va);
/* Evict a page from memory */
void lpage_evict(struct lpage *victim);
Common Usage Patterns
Cleaning Up a Page
/* Example of proper lpage cleanup */
if (lp != NULL) {
/* Remove any TLB entries first */
mmu_unmap(as, page_addr);
/* Then destroy the page */
lpage_destroy(lp);
}
Zero-Filled Pages
When an entry in the lpage array is NULL it means the page is zero-filled. This is a special state that is not in memory or swap, but promised to the user program (and swap has been reserved for it).
When a user program actually accesses a zero-filled page, the VM system must actually instantiate a new page and zero-fill it.
Instantiating a New Zero-Filled Page
When user code accesses a zero-filled page, the VM system must allocate a new page and zero-fill it. This is done using lpage_zerofill when a page fault occurs on a zero-filled page.
Proper Locking
/* Example of correct locking pattern */
lpage_lock(lp);
/* Do operations... */
lpage_unlock(lp);
Important Considerations
Resource Management
- Always free both memory and swap space
- Handle cleanup in error cases
- Check return values from allocation functions
Synchronization
- Use proper locking to prevent races
- Follow lock ordering rules:
- Coremap locks before
lpagelocks - Never hold multiple
lpagelocks - Be careful about lock/unlock ordering
- Coremap locks before
Memory States
- Pages can be:
- In memory (valid physical address)
- In swap (valid swap address)
- Zero-filled (neither; will be zeroed on demand)
- Track state changes correctly
Common Pitfalls
- Resource Leaks
- Forgetting to free swap space
- Not cleaning up on error paths
- Missing
lpage_destroycalls
- Synchronization Issues
- Missing locks
- Wrong lock order
- Double locking
- Not unlocking on all paths
- State Management
- Not handling invalid states
- Assuming pages are in memory
- Not checking return values
Debugging Tips
- Watch for these symptoms:
- Memory leaks
- Page-content corruption
- Deadlocks
- System hangs
- Common error cases:
- NULL pointer dereferences
- Invalid page states
- Lock/unlock mismatches
When Implementing VM Operations
Remember to
- Track all resources that need cleanup
- Handle all error cases gracefully
- Maintain proper synchronization
- Check return values
- Clean up in reverse order of allocation
Example Operation Flow
/*
* Template for operations that manipulate lpages
*/
int some_operation(struct lpage *lp)
{
int result;
/* Lock the page */
lpage_lock(lp);
/* Verify state is valid */
if ([invalid condition]) {
lpage_unlock(lp);
return ERROR;
}
/* Perform operation */
result = do_something();
if (result) {
lpage_unlock(lp);
return result;
}
/* Update state */
update_state();
/* Unlock */
lpage_unlock(lp);
return 0;
}
Remember: The lpage subsystem handles the details of page-content management. Your code should focus on proper resource management and maintaining consistency while using these facilities.
(When logged in, completion status appears here.)