18f09e987SBob Copeland /* 28f09e987SBob Copeland * OMFS (as used by RIO Karma) file operations. 38f09e987SBob Copeland * Copyright (C) 2005 Bob Copeland <me@bobcopeland.com> 48f09e987SBob Copeland * Released under GPL v2. 58f09e987SBob Copeland */ 68f09e987SBob Copeland 78f09e987SBob Copeland #include <linux/version.h> 88f09e987SBob Copeland #include <linux/module.h> 98f09e987SBob Copeland #include <linux/fs.h> 108f09e987SBob Copeland #include <linux/buffer_head.h> 118f09e987SBob Copeland #include <linux/mpage.h> 128f09e987SBob Copeland #include "omfs.h" 138f09e987SBob Copeland 148f09e987SBob Copeland static int omfs_sync_file(struct file *file, struct dentry *dentry, 158f09e987SBob Copeland int datasync) 168f09e987SBob Copeland { 178f09e987SBob Copeland struct inode *inode = dentry->d_inode; 188f09e987SBob Copeland int err; 198f09e987SBob Copeland 208f09e987SBob Copeland err = sync_mapping_buffers(inode->i_mapping); 218f09e987SBob Copeland if (!(inode->i_state & I_DIRTY)) 228f09e987SBob Copeland return err; 238f09e987SBob Copeland if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) 248f09e987SBob Copeland return err; 258f09e987SBob Copeland err |= omfs_sync_inode(inode); 268f09e987SBob Copeland return err ? -EIO : 0; 278f09e987SBob Copeland } 288f09e987SBob Copeland 298f09e987SBob Copeland void omfs_make_empty_table(struct buffer_head *bh, int offset) 308f09e987SBob Copeland { 318f09e987SBob Copeland struct omfs_extent *oe = (struct omfs_extent *) &bh->b_data[offset]; 328f09e987SBob Copeland 33d406f66dSHarvey Harrison oe->e_next = ~cpu_to_be64(0ULL); 348f09e987SBob Copeland oe->e_extent_count = cpu_to_be32(1), 358f09e987SBob Copeland oe->e_fill = cpu_to_be32(0x22), 36d406f66dSHarvey Harrison oe->e_entry.e_cluster = ~cpu_to_be64(0ULL); 37d406f66dSHarvey Harrison oe->e_entry.e_blocks = ~cpu_to_be64(0ULL); 388f09e987SBob Copeland } 398f09e987SBob Copeland 408f09e987SBob Copeland int omfs_shrink_inode(struct inode *inode) 418f09e987SBob Copeland { 428f09e987SBob Copeland struct omfs_sb_info *sbi = OMFS_SB(inode->i_sb); 438f09e987SBob Copeland struct omfs_extent *oe; 448f09e987SBob Copeland struct omfs_extent_entry *entry; 458f09e987SBob Copeland struct buffer_head *bh; 468f09e987SBob Copeland u64 next, last; 478f09e987SBob Copeland u32 extent_count; 488f09e987SBob Copeland int ret; 498f09e987SBob Copeland 508f09e987SBob Copeland /* traverse extent table, freeing each entry that is greater 518f09e987SBob Copeland * than inode->i_size; 528f09e987SBob Copeland */ 538f09e987SBob Copeland next = inode->i_ino; 548f09e987SBob Copeland 558f09e987SBob Copeland /* only support truncate -> 0 for now */ 568f09e987SBob Copeland ret = -EIO; 578f09e987SBob Copeland if (inode->i_size != 0) 588f09e987SBob Copeland goto out; 598f09e987SBob Copeland 608f09e987SBob Copeland bh = sb_bread(inode->i_sb, clus_to_blk(sbi, next)); 618f09e987SBob Copeland if (!bh) 628f09e987SBob Copeland goto out; 638f09e987SBob Copeland 648f09e987SBob Copeland oe = (struct omfs_extent *)(&bh->b_data[OMFS_EXTENT_START]); 658f09e987SBob Copeland 668f09e987SBob Copeland for (;;) { 678f09e987SBob Copeland 688f09e987SBob Copeland if (omfs_is_bad(sbi, (struct omfs_header *) bh->b_data, next)) { 698f09e987SBob Copeland brelse(bh); 708f09e987SBob Copeland goto out; 718f09e987SBob Copeland } 728f09e987SBob Copeland 738f09e987SBob Copeland extent_count = be32_to_cpu(oe->e_extent_count); 748f09e987SBob Copeland last = next; 758f09e987SBob Copeland next = be64_to_cpu(oe->e_next); 768f09e987SBob Copeland entry = &oe->e_entry; 778f09e987SBob Copeland 788f09e987SBob Copeland /* ignore last entry as it is the terminator */ 798f09e987SBob Copeland for (; extent_count > 1; extent_count--) { 808f09e987SBob Copeland u64 start, count; 818f09e987SBob Copeland start = be64_to_cpu(entry->e_cluster); 828f09e987SBob Copeland count = be64_to_cpu(entry->e_blocks); 838f09e987SBob Copeland 848f09e987SBob Copeland omfs_clear_range(inode->i_sb, start, (int) count); 858f09e987SBob Copeland entry++; 868f09e987SBob Copeland } 878f09e987SBob Copeland omfs_make_empty_table(bh, (char *) oe - bh->b_data); 888f09e987SBob Copeland mark_buffer_dirty(bh); 898f09e987SBob Copeland brelse(bh); 908f09e987SBob Copeland 918f09e987SBob Copeland if (last != inode->i_ino) 928f09e987SBob Copeland omfs_clear_range(inode->i_sb, last, sbi->s_mirrors); 938f09e987SBob Copeland 948f09e987SBob Copeland if (next == ~0) 958f09e987SBob Copeland break; 968f09e987SBob Copeland 978f09e987SBob Copeland bh = sb_bread(inode->i_sb, clus_to_blk(sbi, next)); 988f09e987SBob Copeland if (!bh) 998f09e987SBob Copeland goto out; 1008f09e987SBob Copeland oe = (struct omfs_extent *) (&bh->b_data[OMFS_EXTENT_CONT]); 1018f09e987SBob Copeland } 1028f09e987SBob Copeland ret = 0; 1038f09e987SBob Copeland out: 1048f09e987SBob Copeland return ret; 1058f09e987SBob Copeland } 1068f09e987SBob Copeland 1078f09e987SBob Copeland static void omfs_truncate(struct inode *inode) 1088f09e987SBob Copeland { 1098f09e987SBob Copeland omfs_shrink_inode(inode); 1108f09e987SBob Copeland mark_inode_dirty(inode); 1118f09e987SBob Copeland } 1128f09e987SBob Copeland 1138f09e987SBob Copeland /* 1148f09e987SBob Copeland * Add new blocks to the current extent, or create new entries/continuations 1158f09e987SBob Copeland * as necessary. 1168f09e987SBob Copeland */ 1178f09e987SBob Copeland static int omfs_grow_extent(struct inode *inode, struct omfs_extent *oe, 1188f09e987SBob Copeland u64 *ret_block) 1198f09e987SBob Copeland { 1208f09e987SBob Copeland struct omfs_extent_entry *terminator; 1218f09e987SBob Copeland struct omfs_extent_entry *entry = &oe->e_entry; 1228f09e987SBob Copeland struct omfs_sb_info *sbi = OMFS_SB(inode->i_sb); 1238f09e987SBob Copeland u32 extent_count = be32_to_cpu(oe->e_extent_count); 1248f09e987SBob Copeland u64 new_block = 0; 1258f09e987SBob Copeland u32 max_count; 1268f09e987SBob Copeland int new_count; 1278f09e987SBob Copeland int ret = 0; 1288f09e987SBob Copeland 1298f09e987SBob Copeland /* reached the end of the extent table with no blocks mapped. 1308f09e987SBob Copeland * there are three possibilities for adding: grow last extent, 1318f09e987SBob Copeland * add a new extent to the current extent table, and add a 1328f09e987SBob Copeland * continuation inode. in last two cases need an allocator for 1338f09e987SBob Copeland * sbi->s_cluster_size 1348f09e987SBob Copeland */ 1358f09e987SBob Copeland 1368f09e987SBob Copeland /* TODO: handle holes */ 1378f09e987SBob Copeland 1388f09e987SBob Copeland /* should always have a terminator */ 1398f09e987SBob Copeland if (extent_count < 1) 1408f09e987SBob Copeland return -EIO; 1418f09e987SBob Copeland 1428f09e987SBob Copeland /* trivially grow current extent, if next block is not taken */ 1438f09e987SBob Copeland terminator = entry + extent_count - 1; 1448f09e987SBob Copeland if (extent_count > 1) { 1458f09e987SBob Copeland entry = terminator-1; 1468f09e987SBob Copeland new_block = be64_to_cpu(entry->e_cluster) + 1478f09e987SBob Copeland be64_to_cpu(entry->e_blocks); 1488f09e987SBob Copeland 1498f09e987SBob Copeland if (omfs_allocate_block(inode->i_sb, new_block)) { 1508f09e987SBob Copeland entry->e_blocks = 1518f09e987SBob Copeland cpu_to_be64(be64_to_cpu(entry->e_blocks) + 1); 1528f09e987SBob Copeland terminator->e_blocks = ~(cpu_to_be64( 1538f09e987SBob Copeland be64_to_cpu(~terminator->e_blocks) + 1)); 1548f09e987SBob Copeland goto out; 1558f09e987SBob Copeland } 1568f09e987SBob Copeland } 1578f09e987SBob Copeland max_count = (sbi->s_sys_blocksize - OMFS_EXTENT_START - 1588f09e987SBob Copeland sizeof(struct omfs_extent)) / 1598f09e987SBob Copeland sizeof(struct omfs_extent_entry) + 1; 1608f09e987SBob Copeland 1618f09e987SBob Copeland /* TODO: add a continuation block here */ 1628f09e987SBob Copeland if (be32_to_cpu(oe->e_extent_count) > max_count-1) 1638f09e987SBob Copeland return -EIO; 1648f09e987SBob Copeland 1658f09e987SBob Copeland /* try to allocate a new cluster */ 1668f09e987SBob Copeland ret = omfs_allocate_range(inode->i_sb, 1, sbi->s_clustersize, 1678f09e987SBob Copeland &new_block, &new_count); 1688f09e987SBob Copeland if (ret) 1698f09e987SBob Copeland goto out_fail; 1708f09e987SBob Copeland 1718f09e987SBob Copeland /* copy terminator down an entry */ 1728f09e987SBob Copeland entry = terminator; 1738f09e987SBob Copeland terminator++; 1748f09e987SBob Copeland memcpy(terminator, entry, sizeof(struct omfs_extent_entry)); 1758f09e987SBob Copeland 1768f09e987SBob Copeland entry->e_cluster = cpu_to_be64(new_block); 1778f09e987SBob Copeland entry->e_blocks = cpu_to_be64((u64) new_count); 1788f09e987SBob Copeland 1798f09e987SBob Copeland terminator->e_blocks = ~(cpu_to_be64( 1808f09e987SBob Copeland be64_to_cpu(~terminator->e_blocks) + (u64) new_count)); 1818f09e987SBob Copeland 1828f09e987SBob Copeland /* write in new entry */ 1838f09e987SBob Copeland oe->e_extent_count = cpu_to_be32(1 + be32_to_cpu(oe->e_extent_count)); 1848f09e987SBob Copeland 1858f09e987SBob Copeland out: 1868f09e987SBob Copeland *ret_block = new_block; 1878f09e987SBob Copeland out_fail: 1888f09e987SBob Copeland return ret; 1898f09e987SBob Copeland } 1908f09e987SBob Copeland 1918f09e987SBob Copeland /* 1928f09e987SBob Copeland * Scans across the directory table for a given file block number. 1938f09e987SBob Copeland * If block not found, return 0. 1948f09e987SBob Copeland */ 1958f09e987SBob Copeland static sector_t find_block(struct inode *inode, struct omfs_extent_entry *ent, 1968f09e987SBob Copeland sector_t block, int count, int *left) 1978f09e987SBob Copeland { 1988f09e987SBob Copeland /* count > 1 because of terminator */ 1998f09e987SBob Copeland sector_t searched = 0; 2008f09e987SBob Copeland for (; count > 1; count--) { 2018f09e987SBob Copeland int numblocks = clus_to_blk(OMFS_SB(inode->i_sb), 2028f09e987SBob Copeland be64_to_cpu(ent->e_blocks)); 2038f09e987SBob Copeland 2048f09e987SBob Copeland if (block >= searched && 2058f09e987SBob Copeland block < searched + numblocks) { 2068f09e987SBob Copeland /* 2078f09e987SBob Copeland * found it at cluster + (block - searched) 2088f09e987SBob Copeland * numblocks - (block - searched) is remainder 2098f09e987SBob Copeland */ 2108f09e987SBob Copeland *left = numblocks - (block - searched); 2118f09e987SBob Copeland return clus_to_blk(OMFS_SB(inode->i_sb), 2128f09e987SBob Copeland be64_to_cpu(ent->e_cluster)) + 2138f09e987SBob Copeland block - searched; 2148f09e987SBob Copeland } 2158f09e987SBob Copeland searched += numblocks; 2168f09e987SBob Copeland ent++; 2178f09e987SBob Copeland } 2188f09e987SBob Copeland return 0; 2198f09e987SBob Copeland } 2208f09e987SBob Copeland 2218f09e987SBob Copeland static int omfs_get_block(struct inode *inode, sector_t block, 2228f09e987SBob Copeland struct buffer_head *bh_result, int create) 2238f09e987SBob Copeland { 2248f09e987SBob Copeland struct buffer_head *bh; 2258f09e987SBob Copeland sector_t next, offset; 2268f09e987SBob Copeland int ret; 2278f09e987SBob Copeland u64 new_block; 2288f09e987SBob Copeland int extent_count; 2298f09e987SBob Copeland struct omfs_extent *oe; 2308f09e987SBob Copeland struct omfs_extent_entry *entry; 2318f09e987SBob Copeland struct omfs_sb_info *sbi = OMFS_SB(inode->i_sb); 2328f09e987SBob Copeland int max_blocks = bh_result->b_size >> inode->i_blkbits; 2338f09e987SBob Copeland int remain; 2348f09e987SBob Copeland 2358f09e987SBob Copeland ret = -EIO; 2368f09e987SBob Copeland bh = sb_bread(inode->i_sb, clus_to_blk(sbi, inode->i_ino)); 2378f09e987SBob Copeland if (!bh) 2388f09e987SBob Copeland goto out; 2398f09e987SBob Copeland 2408f09e987SBob Copeland oe = (struct omfs_extent *)(&bh->b_data[OMFS_EXTENT_START]); 2418f09e987SBob Copeland next = inode->i_ino; 2428f09e987SBob Copeland 2438f09e987SBob Copeland for (;;) { 2448f09e987SBob Copeland 2458f09e987SBob Copeland if (omfs_is_bad(sbi, (struct omfs_header *) bh->b_data, next)) 2468f09e987SBob Copeland goto out_brelse; 2478f09e987SBob Copeland 2488f09e987SBob Copeland extent_count = be32_to_cpu(oe->e_extent_count); 2498f09e987SBob Copeland next = be64_to_cpu(oe->e_next); 2508f09e987SBob Copeland entry = &oe->e_entry; 2518f09e987SBob Copeland 2528f09e987SBob Copeland offset = find_block(inode, entry, block, extent_count, &remain); 2538f09e987SBob Copeland if (offset > 0) { 2548f09e987SBob Copeland ret = 0; 2558f09e987SBob Copeland map_bh(bh_result, inode->i_sb, offset); 2568f09e987SBob Copeland if (remain > max_blocks) 2578f09e987SBob Copeland remain = max_blocks; 2588f09e987SBob Copeland bh_result->b_size = (remain << inode->i_blkbits); 2598f09e987SBob Copeland goto out_brelse; 2608f09e987SBob Copeland } 2618f09e987SBob Copeland if (next == ~0) 2628f09e987SBob Copeland break; 2638f09e987SBob Copeland 2648f09e987SBob Copeland brelse(bh); 2658f09e987SBob Copeland bh = sb_bread(inode->i_sb, clus_to_blk(sbi, next)); 2668f09e987SBob Copeland if (!bh) 2678f09e987SBob Copeland goto out; 2688f09e987SBob Copeland oe = (struct omfs_extent *) (&bh->b_data[OMFS_EXTENT_CONT]); 2698f09e987SBob Copeland } 2708f09e987SBob Copeland if (create) { 2718f09e987SBob Copeland ret = omfs_grow_extent(inode, oe, &new_block); 2728f09e987SBob Copeland if (ret == 0) { 2738f09e987SBob Copeland mark_buffer_dirty(bh); 2748f09e987SBob Copeland mark_inode_dirty(inode); 2758f09e987SBob Copeland map_bh(bh_result, inode->i_sb, 2768f09e987SBob Copeland clus_to_blk(sbi, new_block)); 2778f09e987SBob Copeland } 2788f09e987SBob Copeland } 2798f09e987SBob Copeland out_brelse: 2808f09e987SBob Copeland brelse(bh); 2818f09e987SBob Copeland out: 2828f09e987SBob Copeland return ret; 2838f09e987SBob Copeland } 2848f09e987SBob Copeland 2858f09e987SBob Copeland static int omfs_readpage(struct file *file, struct page *page) 2868f09e987SBob Copeland { 2878f09e987SBob Copeland return block_read_full_page(page, omfs_get_block); 2888f09e987SBob Copeland } 2898f09e987SBob Copeland 2908f09e987SBob Copeland static int omfs_readpages(struct file *file, struct address_space *mapping, 2918f09e987SBob Copeland struct list_head *pages, unsigned nr_pages) 2928f09e987SBob Copeland { 2938f09e987SBob Copeland return mpage_readpages(mapping, pages, nr_pages, omfs_get_block); 2948f09e987SBob Copeland } 2958f09e987SBob Copeland 2968f09e987SBob Copeland static int omfs_writepage(struct page *page, struct writeback_control *wbc) 2978f09e987SBob Copeland { 2988f09e987SBob Copeland return block_write_full_page(page, omfs_get_block, wbc); 2998f09e987SBob Copeland } 3008f09e987SBob Copeland 3018f09e987SBob Copeland static int 3028f09e987SBob Copeland omfs_writepages(struct address_space *mapping, struct writeback_control *wbc) 3038f09e987SBob Copeland { 3048f09e987SBob Copeland return mpage_writepages(mapping, wbc, omfs_get_block); 3058f09e987SBob Copeland } 3068f09e987SBob Copeland 3078f09e987SBob Copeland static int omfs_write_begin(struct file *file, struct address_space *mapping, 3088f09e987SBob Copeland loff_t pos, unsigned len, unsigned flags, 3098f09e987SBob Copeland struct page **pagep, void **fsdata) 3108f09e987SBob Copeland { 3118f09e987SBob Copeland *pagep = NULL; 3128f09e987SBob Copeland return block_write_begin(file, mapping, pos, len, flags, 3138f09e987SBob Copeland pagep, fsdata, omfs_get_block); 3148f09e987SBob Copeland } 3158f09e987SBob Copeland 3168f09e987SBob Copeland static sector_t omfs_bmap(struct address_space *mapping, sector_t block) 3178f09e987SBob Copeland { 3188f09e987SBob Copeland return generic_block_bmap(mapping, block, omfs_get_block); 3198f09e987SBob Copeland } 3208f09e987SBob Copeland 3218f09e987SBob Copeland struct file_operations omfs_file_operations = { 3228f09e987SBob Copeland .llseek = generic_file_llseek, 3238f09e987SBob Copeland .read = do_sync_read, 3248f09e987SBob Copeland .write = do_sync_write, 3258f09e987SBob Copeland .aio_read = generic_file_aio_read, 3268f09e987SBob Copeland .aio_write = generic_file_aio_write, 3278f09e987SBob Copeland .mmap = generic_file_mmap, 3288f09e987SBob Copeland .fsync = omfs_sync_file, 3298f09e987SBob Copeland .splice_read = generic_file_splice_read, 3308f09e987SBob Copeland }; 3318f09e987SBob Copeland 3328f09e987SBob Copeland struct inode_operations omfs_file_inops = { 3338f09e987SBob Copeland .truncate = omfs_truncate 3348f09e987SBob Copeland }; 3358f09e987SBob Copeland 3368f09e987SBob Copeland struct address_space_operations omfs_aops = { 3378f09e987SBob Copeland .readpage = omfs_readpage, 3388f09e987SBob Copeland .readpages = omfs_readpages, 3398f09e987SBob Copeland .writepage = omfs_writepage, 3408f09e987SBob Copeland .writepages = omfs_writepages, 3418f09e987SBob Copeland .sync_page = block_sync_page, 3428f09e987SBob Copeland .write_begin = omfs_write_begin, 3438f09e987SBob Copeland .write_end = generic_write_end, 3448f09e987SBob Copeland .bmap = omfs_bmap, 3458f09e987SBob Copeland }; 3468f09e987SBob Copeland 347