11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * fs/bfs/file.c 31da177e4SLinus Torvalds * BFS file operations. 41da177e4SLinus Torvalds * Copyright (C) 1999,2000 Tigran Aivazian <tigran@veritas.com> 51da177e4SLinus Torvalds */ 61da177e4SLinus Torvalds 71da177e4SLinus Torvalds #include <linux/fs.h> 81da177e4SLinus Torvalds #include <linux/buffer_head.h> 91da177e4SLinus Torvalds #include <linux/smp_lock.h> 101da177e4SLinus Torvalds #include "bfs.h" 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds #undef DEBUG 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds #ifdef DEBUG 151da177e4SLinus Torvalds #define dprintf(x...) printf(x) 161da177e4SLinus Torvalds #else 171da177e4SLinus Torvalds #define dprintf(x...) 181da177e4SLinus Torvalds #endif 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds struct file_operations bfs_file_operations = { 211da177e4SLinus Torvalds .llseek = generic_file_llseek, 221da177e4SLinus Torvalds .read = generic_file_read, 231da177e4SLinus Torvalds .write = generic_file_write, 241da177e4SLinus Torvalds .mmap = generic_file_mmap, 251da177e4SLinus Torvalds .sendfile = generic_file_sendfile, 261da177e4SLinus Torvalds }; 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds static int bfs_move_block(unsigned long from, unsigned long to, struct super_block *sb) 291da177e4SLinus Torvalds { 301da177e4SLinus Torvalds struct buffer_head *bh, *new; 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds bh = sb_bread(sb, from); 331da177e4SLinus Torvalds if (!bh) 341da177e4SLinus Torvalds return -EIO; 351da177e4SLinus Torvalds new = sb_getblk(sb, to); 361da177e4SLinus Torvalds memcpy(new->b_data, bh->b_data, bh->b_size); 371da177e4SLinus Torvalds mark_buffer_dirty(new); 381da177e4SLinus Torvalds bforget(bh); 391da177e4SLinus Torvalds brelse(new); 401da177e4SLinus Torvalds return 0; 411da177e4SLinus Torvalds } 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds static int bfs_move_blocks(struct super_block *sb, unsigned long start, unsigned long end, 441da177e4SLinus Torvalds unsigned long where) 451da177e4SLinus Torvalds { 461da177e4SLinus Torvalds unsigned long i; 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds dprintf("%08lx-%08lx->%08lx\n", start, end, where); 491da177e4SLinus Torvalds for (i = start; i <= end; i++) 501da177e4SLinus Torvalds if(bfs_move_block(i, where + i, sb)) { 511da177e4SLinus Torvalds dprintf("failed to move block %08lx -> %08lx\n", i, where + i); 521da177e4SLinus Torvalds return -EIO; 531da177e4SLinus Torvalds } 541da177e4SLinus Torvalds return 0; 551da177e4SLinus Torvalds } 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds static int bfs_get_block(struct inode * inode, sector_t block, 581da177e4SLinus Torvalds struct buffer_head * bh_result, int create) 591da177e4SLinus Torvalds { 601da177e4SLinus Torvalds long phys; 611da177e4SLinus Torvalds int err; 621da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 631da177e4SLinus Torvalds struct bfs_sb_info *info = BFS_SB(sb); 641da177e4SLinus Torvalds struct bfs_inode_info *bi = BFS_I(inode); 651da177e4SLinus Torvalds struct buffer_head *sbh = info->si_sbh; 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds if (block < 0 || block > info->si_blocks) 681da177e4SLinus Torvalds return -EIO; 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds phys = bi->i_sblock + block; 711da177e4SLinus Torvalds if (!create) { 721da177e4SLinus Torvalds if (phys <= bi->i_eblock) { 731da177e4SLinus Torvalds dprintf("c=%d, b=%08lx, phys=%08lx (granted)\n", create, block, phys); 741da177e4SLinus Torvalds map_bh(bh_result, sb, phys); 751da177e4SLinus Torvalds } 761da177e4SLinus Torvalds return 0; 771da177e4SLinus Torvalds } 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds /* if the file is not empty and the requested block is within the range 801da177e4SLinus Torvalds of blocks allocated for this file, we can grant it */ 811da177e4SLinus Torvalds if (inode->i_size && phys <= bi->i_eblock) { 821da177e4SLinus Torvalds dprintf("c=%d, b=%08lx, phys=%08lx (interim block granted)\n", 831da177e4SLinus Torvalds create, block, phys); 841da177e4SLinus Torvalds map_bh(bh_result, sb, phys); 851da177e4SLinus Torvalds return 0; 861da177e4SLinus Torvalds } 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds /* the rest has to be protected against itself */ 891da177e4SLinus Torvalds lock_kernel(); 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds /* if the last data block for this file is the last allocated block, we can 921da177e4SLinus Torvalds extend the file trivially, without moving it anywhere */ 931da177e4SLinus Torvalds if (bi->i_eblock == info->si_lf_eblk) { 941da177e4SLinus Torvalds dprintf("c=%d, b=%08lx, phys=%08lx (simple extension)\n", 951da177e4SLinus Torvalds create, block, phys); 961da177e4SLinus Torvalds map_bh(bh_result, sb, phys); 971da177e4SLinus Torvalds info->si_freeb -= phys - bi->i_eblock; 981da177e4SLinus Torvalds info->si_lf_eblk = bi->i_eblock = phys; 991da177e4SLinus Torvalds mark_inode_dirty(inode); 1001da177e4SLinus Torvalds mark_buffer_dirty(sbh); 1011da177e4SLinus Torvalds err = 0; 1021da177e4SLinus Torvalds goto out; 1031da177e4SLinus Torvalds } 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds /* Ok, we have to move this entire file to the next free block */ 1061da177e4SLinus Torvalds phys = info->si_lf_eblk + 1; 1071da177e4SLinus Torvalds if (bi->i_sblock) { /* if data starts on block 0 then there is no data */ 1081da177e4SLinus Torvalds err = bfs_move_blocks(inode->i_sb, bi->i_sblock, 1091da177e4SLinus Torvalds bi->i_eblock, phys); 1101da177e4SLinus Torvalds if (err) { 1111da177e4SLinus Torvalds dprintf("failed to move ino=%08lx -> fs corruption\n", inode->i_ino); 1121da177e4SLinus Torvalds goto out; 1131da177e4SLinus Torvalds } 1141da177e4SLinus Torvalds } else 1151da177e4SLinus Torvalds err = 0; 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds dprintf("c=%d, b=%08lx, phys=%08lx (moved)\n", create, block, phys); 1181da177e4SLinus Torvalds bi->i_sblock = phys; 1191da177e4SLinus Torvalds phys += block; 1201da177e4SLinus Torvalds info->si_lf_eblk = bi->i_eblock = phys; 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds /* this assumes nothing can write the inode back while we are here 1231da177e4SLinus Torvalds * and thus update inode->i_blocks! (XXX)*/ 1241da177e4SLinus Torvalds info->si_freeb -= bi->i_eblock - bi->i_sblock + 1 - inode->i_blocks; 1251da177e4SLinus Torvalds mark_inode_dirty(inode); 1261da177e4SLinus Torvalds mark_buffer_dirty(sbh); 1271da177e4SLinus Torvalds map_bh(bh_result, sb, phys); 1281da177e4SLinus Torvalds out: 1291da177e4SLinus Torvalds unlock_kernel(); 1301da177e4SLinus Torvalds return err; 1311da177e4SLinus Torvalds } 1321da177e4SLinus Torvalds 1331da177e4SLinus Torvalds static int bfs_writepage(struct page *page, struct writeback_control *wbc) 1341da177e4SLinus Torvalds { 1351da177e4SLinus Torvalds return block_write_full_page(page, bfs_get_block, wbc); 1361da177e4SLinus Torvalds } 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds static int bfs_readpage(struct file *file, struct page *page) 1391da177e4SLinus Torvalds { 1401da177e4SLinus Torvalds return block_read_full_page(page, bfs_get_block); 1411da177e4SLinus Torvalds } 1421da177e4SLinus Torvalds 1431da177e4SLinus Torvalds static int bfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) 1441da177e4SLinus Torvalds { 1451da177e4SLinus Torvalds return block_prepare_write(page, from, to, bfs_get_block); 1461da177e4SLinus Torvalds } 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds static sector_t bfs_bmap(struct address_space *mapping, sector_t block) 1491da177e4SLinus Torvalds { 1501da177e4SLinus Torvalds return generic_block_bmap(mapping, block, bfs_get_block); 1511da177e4SLinus Torvalds } 1521da177e4SLinus Torvalds 1531da177e4SLinus Torvalds struct address_space_operations bfs_aops = { 1541da177e4SLinus Torvalds .readpage = bfs_readpage, 1551da177e4SLinus Torvalds .writepage = bfs_writepage, 1561da177e4SLinus Torvalds .sync_page = block_sync_page, 1571da177e4SLinus Torvalds .prepare_write = bfs_prepare_write, 1581da177e4SLinus Torvalds .commit_write = generic_commit_write, 1591da177e4SLinus Torvalds .bmap = bfs_bmap, 1601da177e4SLinus Torvalds }; 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds struct inode_operations bfs_file_inops; 163