/* * vat.c * * PURPOSE * Virtual Allocation Table (VAT) management routines. * * DESCRIPTION * This code uses a single page for a page directory, so the maximum size * of a VAT is limited (examples: 4MB on i386, 16MB on Alpha). This is a * reasonable limit. * * Unused page directory entries are marked with a NULL, and unused block * entries on a page are marked with 0xffffffff. * * HISTORY * November 27, 1997 - Andrew E. Mileski * Credit Rob Sims with the page table idea, and blame me for the code. */ #include #include #include #include #define PGDIR_PAGES (PAGE_SIZE / sizeof(__u32 *)) #define PG_MASK (PAGE_MASK >> 2) #define PG_SHIFT (PAGE_SHIFT - 2) /* * udf_vat_bmap * * PURPOSE * By using the VAT, map a virtual block address to a real block address. * * HISTORY * November 27, 1997 - Andrew E. Mileski * Credit Rob Sims with the page table idea, and blame me for the code. */ extern __u32 * udf_vat_bmap(struct super_block *sb, __u32 block) { unsigned pgdir_levels, pg_index, pgdir_index; __u32 **pgdir; pgdir = UDF_SB(sb)->s_vat; /* If necessary, create a page directory */ if (!pgdir) { pgdir = (__u32 **)get_free_page(GFP_KERNEL); if (!page_dir) { printk(KERN_ERR "udf: can't allocate VAT page directory\n"); return NULL; } UDF_SB(sb)->s_vat = page_dir; } /* This is a lot faster than searching a list - thanks Rob! */ pg_index = block & PG_MASK; pgdir_index = block >> PG_SHIFT; /* Check for a huge VAT */ while (pgdir_index >= PGDIR_PAGES) { printk(KERN_ERR "udf: huge VAT (%d)\n", block); return NULL; } /* If necessary, add a page to the VAT */ if (!pgdir[pgdir_index]) { __u32 *new_page; new_page = (___u32 *)__get_free_page(GFP_KERNEL); if (!new_page) { printk(KERN_ERR "udf: can't allocate VAT page\n"); return NULL; } memset(new_page, 0xff, PAGE_SIZE); pgdir[pgdir_index] = new_page; } return pgdir[pgdir_index] + pg_index; } /* * udf_vat_free * * PURPOSE * Free all memory associated with the VAT. * * HISTORY * November 27, 1997 - Andrew E. Mileski * Credit Rob Sims with the page table idea, and blame me for the code. */ extern void udf_vat_free(struct super_block *sb) { unsigned page; __u32 **pgdir; pgdir = UDF_SB(sb)->s_vat; if (pgdir) { for (page = 0; page < PGDIR_PAGES; page++) { if (pgdir[page]) free_page(page); } free_page(page_dir); UDF_SB(sb)->s_vat = NULL; } } #if 0 extern int udf_vat_read(struct super_block *sb) { } extern int udf_vat_write(struct super_block *sb) { } #endif