1/* 2 * fs/bfs/file.c 3 * BFS file operations. 4 * Copyright (C) 1999,2000 Tigran Aivazian <tigran@veritas.com> 5 * 6 * Make the file block allocation algorithm understand the size 7 * of the underlying block device. 8 * Copyright (C) 2007 Dmitri Vorobiev <dmitri.vorobiev@gmail.com> 9 * 10 */ 11 12#include <linux/fs.h> 13#include <linux/buffer_head.h> 14#include "bfs.h" 15 16#undef DEBUG 17 18#ifdef DEBUG 19#define dprintf(x...) printf(x) 20#else 21#define dprintf(x...) 22#endif 23 24const struct file_operations bfs_file_operations = { 25 .llseek = generic_file_llseek, 26 .read_iter = generic_file_read_iter, 27 .write_iter = generic_file_write_iter, 28 .mmap = generic_file_mmap, 29 .splice_read = generic_file_splice_read, 30}; 31 32static int bfs_move_block(unsigned long from, unsigned long to, 33 struct super_block *sb) 34{ 35 struct buffer_head *bh, *new; 36 37 bh = sb_bread(sb, from); 38 if (!bh) 39 return -EIO; 40 new = sb_getblk(sb, to); 41 memcpy(new->b_data, bh->b_data, bh->b_size); 42 mark_buffer_dirty(new); 43 bforget(bh); 44 brelse(new); 45 return 0; 46} 47 48static int bfs_move_blocks(struct super_block *sb, unsigned long start, 49 unsigned long end, unsigned long where) 50{ 51 unsigned long i; 52 53 dprintf("%08lx-%08lx->%08lx\n", start, end, where); 54 for (i = start; i <= end; i++) 55 if(bfs_move_block(i, where + i, sb)) { 56 dprintf("failed to move block %08lx -> %08lx\n", i, 57 where + i); 58 return -EIO; 59 } 60 return 0; 61} 62 63static int bfs_get_block(struct inode *inode, sector_t block, 64 struct buffer_head *bh_result, int create) 65{ 66 unsigned long phys; 67 int err; 68 struct super_block *sb = inode->i_sb; 69 struct bfs_sb_info *info = BFS_SB(sb); 70 struct bfs_inode_info *bi = BFS_I(inode); 71 72 phys = bi->i_sblock + block; 73 if (!create) { 74 if (phys <= bi->i_eblock) { 75 dprintf("c=%d, b=%08lx, phys=%09lx (granted)\n", 76 create, (unsigned long)block, phys); 77 map_bh(bh_result, sb, phys); 78 } 79 return 0; 80 } 81 82 /* 83 * If the file is not empty and the requested block is within the 84 * range of blocks allocated for this file, we can grant it. 85 */ 86 if (bi->i_sblock && (phys <= bi->i_eblock)) { 87 dprintf("c=%d, b=%08lx, phys=%08lx (interim block granted)\n", 88 create, (unsigned long)block, phys); 89 map_bh(bh_result, sb, phys); 90 return 0; 91 } 92 93 /* The file will be extended, so let's see if there is enough space. */ 94 if (phys >= info->si_blocks) 95 return -ENOSPC; 96 97 /* The rest has to be protected against itself. */ 98 mutex_lock(&info->bfs_lock); 99 100 /* 101 * If the last data block for this file is the last allocated 102 * block, we can extend the file trivially, without moving it 103 * anywhere. 104 */ 105 if (bi->i_eblock == info->si_lf_eblk) { 106 dprintf("c=%d, b=%08lx, phys=%08lx (simple extension)\n", 107 create, (unsigned long)block, phys); 108 map_bh(bh_result, sb, phys); 109 info->si_freeb -= phys - bi->i_eblock; 110 info->si_lf_eblk = bi->i_eblock = phys; 111 mark_inode_dirty(inode); 112 err = 0; 113 goto out; 114 } 115 116 /* Ok, we have to move this entire file to the next free block. */ 117 phys = info->si_lf_eblk + 1; 118 if (phys + block >= info->si_blocks) { 119 err = -ENOSPC; 120 goto out; 121 } 122 123 if (bi->i_sblock) { 124 err = bfs_move_blocks(inode->i_sb, bi->i_sblock, 125 bi->i_eblock, phys); 126 if (err) { 127 dprintf("failed to move ino=%08lx -> fs corruption\n", 128 inode->i_ino); 129 goto out; 130 } 131 } else 132 err = 0; 133 134 dprintf("c=%d, b=%08lx, phys=%08lx (moved)\n", 135 create, (unsigned long)block, phys); 136 bi->i_sblock = phys; 137 phys += block; 138 info->si_lf_eblk = bi->i_eblock = phys; 139 140 /* 141 * This assumes nothing can write the inode back while we are here 142 * and thus update inode->i_blocks! (XXX) 143 */ 144 info->si_freeb -= bi->i_eblock - bi->i_sblock + 1 - inode->i_blocks; 145 mark_inode_dirty(inode); 146 map_bh(bh_result, sb, phys); 147out: 148 mutex_unlock(&info->bfs_lock); 149 return err; 150} 151 152static int bfs_writepage(struct page *page, struct writeback_control *wbc) 153{ 154 return block_write_full_page(page, bfs_get_block, wbc); 155} 156 157static int bfs_readpage(struct file *file, struct page *page) 158{ 159 return block_read_full_page(page, bfs_get_block); 160} 161 162static void bfs_write_failed(struct address_space *mapping, loff_t to) 163{ 164 struct inode *inode = mapping->host; 165 166 if (to > inode->i_size) 167 truncate_pagecache(inode, inode->i_size); 168} 169 170static int bfs_write_begin(struct file *file, struct address_space *mapping, 171 loff_t pos, unsigned len, unsigned flags, 172 struct page **pagep, void **fsdata) 173{ 174 int ret; 175 176 ret = block_write_begin(mapping, pos, len, flags, pagep, 177 bfs_get_block); 178 if (unlikely(ret)) 179 bfs_write_failed(mapping, pos + len); 180 181 return ret; 182} 183 184static sector_t bfs_bmap(struct address_space *mapping, sector_t block) 185{ 186 return generic_block_bmap(mapping, block, bfs_get_block); 187} 188 189const struct address_space_operations bfs_aops = { 190 .readpage = bfs_readpage, 191 .writepage = bfs_writepage, 192 .write_begin = bfs_write_begin, 193 .write_end = generic_write_end, 194 .bmap = bfs_bmap, 195}; 196 197const struct inode_operations bfs_file_inops; 198