linux/fs/bfs/file.c
<<
>>
Prefs
   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           = do_sync_read,
  27        .aio_read       = generic_file_aio_read,
  28        .write          = do_sync_write,
  29        .aio_write      = generic_file_aio_write,
  30        .mmap           = generic_file_mmap,
  31        .splice_read    = generic_file_splice_read,
  32};
  33
  34static int bfs_move_block(unsigned long from, unsigned long to,
  35                                        struct super_block *sb)
  36{
  37        struct buffer_head *bh, *new;
  38
  39        bh = sb_bread(sb, from);
  40        if (!bh)
  41                return -EIO;
  42        new = sb_getblk(sb, to);
  43        memcpy(new->b_data, bh->b_data, bh->b_size);
  44        mark_buffer_dirty(new);
  45        bforget(bh);
  46        brelse(new);
  47        return 0;
  48}
  49
  50static int bfs_move_blocks(struct super_block *sb, unsigned long start,
  51                                unsigned long end, unsigned long where)
  52{
  53        unsigned long i;
  54
  55        dprintf("%08lx-%08lx->%08lx\n", start, end, where);
  56        for (i = start; i <= end; i++)
  57                if(bfs_move_block(i, where + i, sb)) {
  58                        dprintf("failed to move block %08lx -> %08lx\n", i,
  59                                                                where + i);
  60                        return -EIO;
  61                }
  62        return 0;
  63}
  64
  65static int bfs_get_block(struct inode *inode, sector_t block,
  66                        struct buffer_head *bh_result, int create)
  67{
  68        unsigned long phys;
  69        int err;
  70        struct super_block *sb = inode->i_sb;
  71        struct bfs_sb_info *info = BFS_SB(sb);
  72        struct bfs_inode_info *bi = BFS_I(inode);
  73        struct buffer_head *sbh = info->si_sbh;
  74
  75        phys = bi->i_sblock + block;
  76        if (!create) {
  77                if (phys <= bi->i_eblock) {
  78                        dprintf("c=%d, b=%08lx, phys=%09lx (granted)\n",
  79                                create, (unsigned long)block, phys);
  80                        map_bh(bh_result, sb, phys);
  81                }
  82                return 0;
  83        }
  84
  85        /*
  86         * If the file is not empty and the requested block is within the
  87         * range of blocks allocated for this file, we can grant it.
  88         */
  89        if (bi->i_sblock && (phys <= bi->i_eblock)) {
  90                dprintf("c=%d, b=%08lx, phys=%08lx (interim block granted)\n", 
  91                                create, (unsigned long)block, phys);
  92                map_bh(bh_result, sb, phys);
  93                return 0;
  94        }
  95
  96        /* The file will be extended, so let's see if there is enough space. */
  97        if (phys >= info->si_blocks)
  98                return -ENOSPC;
  99
 100        /* The rest has to be protected against itself. */
 101        mutex_lock(&info->bfs_lock);
 102
 103        /*
 104         * If the last data block for this file is the last allocated
 105         * block, we can extend the file trivially, without moving it
 106         * anywhere.
 107         */
 108        if (bi->i_eblock == info->si_lf_eblk) {
 109                dprintf("c=%d, b=%08lx, phys=%08lx (simple extension)\n", 
 110                                create, (unsigned long)block, phys);
 111                map_bh(bh_result, sb, phys);
 112                info->si_freeb -= phys - bi->i_eblock;
 113                info->si_lf_eblk = bi->i_eblock = phys;
 114                mark_inode_dirty(inode);
 115                mark_buffer_dirty(sbh);
 116                err = 0;
 117                goto out;
 118        }
 119
 120        /* Ok, we have to move this entire file to the next free block. */
 121        phys = info->si_lf_eblk + 1;
 122        if (phys + block >= info->si_blocks) {
 123                err = -ENOSPC;
 124                goto out;
 125        }
 126
 127        if (bi->i_sblock) {
 128                err = bfs_move_blocks(inode->i_sb, bi->i_sblock, 
 129                                                bi->i_eblock, phys);
 130                if (err) {
 131                        dprintf("failed to move ino=%08lx -> fs corruption\n",
 132                                                                inode->i_ino);
 133                        goto out;
 134                }
 135        } else
 136                err = 0;
 137
 138        dprintf("c=%d, b=%08lx, phys=%08lx (moved)\n",
 139                create, (unsigned long)block, phys);
 140        bi->i_sblock = phys;
 141        phys += block;
 142        info->si_lf_eblk = bi->i_eblock = phys;
 143
 144        /*
 145         * This assumes nothing can write the inode back while we are here
 146         * and thus update inode->i_blocks! (XXX)
 147         */
 148        info->si_freeb -= bi->i_eblock - bi->i_sblock + 1 - inode->i_blocks;
 149        mark_inode_dirty(inode);
 150        mark_buffer_dirty(sbh);
 151        map_bh(bh_result, sb, phys);
 152out:
 153        mutex_unlock(&info->bfs_lock);
 154        return err;
 155}
 156
 157static int bfs_writepage(struct page *page, struct writeback_control *wbc)
 158{
 159        return block_write_full_page(page, bfs_get_block, wbc);
 160}
 161
 162static int bfs_readpage(struct file *file, struct page *page)
 163{
 164        return block_read_full_page(page, bfs_get_block);
 165}
 166
 167static int bfs_write_begin(struct file *file, struct address_space *mapping,
 168                        loff_t pos, unsigned len, unsigned flags,
 169                        struct page **pagep, void **fsdata)
 170{
 171        *pagep = NULL;
 172        return block_write_begin(file, mapping, pos, len, flags,
 173                                        pagep, fsdata, bfs_get_block);
 174}
 175
 176static sector_t bfs_bmap(struct address_space *mapping, sector_t block)
 177{
 178        return generic_block_bmap(mapping, block, bfs_get_block);
 179}
 180
 181const struct address_space_operations bfs_aops = {
 182        .readpage       = bfs_readpage,
 183        .writepage      = bfs_writepage,
 184        .sync_page      = block_sync_page,
 185        .write_begin    = bfs_write_begin,
 186        .write_end      = generic_write_end,
 187        .bmap           = bfs_bmap,
 188};
 189
 190const struct inode_operations bfs_file_inops;
 191
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.