linux/fs/omfs/file.c
<<
>>
Prefs
   1/*
   2 * OMFS (as used by RIO Karma) file operations.
   3 * Copyright (C) 2005 Bob Copeland <me@bobcopeland.com>
   4 * Released under GPL v2.
   5 */
   6
   7#include <linux/module.h>
   8#include <linux/fs.h>
   9#include <linux/buffer_head.h>
  10#include <linux/mpage.h>
  11#include "omfs.h"
  12
  13static u32 omfs_max_extents(struct omfs_sb_info *sbi, int offset)
  14{
  15        return (sbi->s_sys_blocksize - offset -
  16                sizeof(struct omfs_extent)) /
  17                sizeof(struct omfs_extent_entry) + 1;
  18}
  19
  20void omfs_make_empty_table(struct buffer_head *bh, int offset)
  21{
  22        struct omfs_extent *oe = (struct omfs_extent *) &bh->b_data[offset];
  23
  24        oe->e_next = ~cpu_to_be64(0ULL);
  25        oe->e_extent_count = cpu_to_be32(1),
  26        oe->e_fill = cpu_to_be32(0x22),
  27        oe->e_entry.e_cluster = ~cpu_to_be64(0ULL);
  28        oe->e_entry.e_blocks = ~cpu_to_be64(0ULL);
  29}
  30
  31int omfs_shrink_inode(struct inode *inode)
  32{
  33        struct omfs_sb_info *sbi = OMFS_SB(inode->i_sb);
  34        struct omfs_extent *oe;
  35        struct omfs_extent_entry *entry;
  36        struct buffer_head *bh;
  37        u64 next, last;
  38        u32 extent_count;
  39        u32 max_extents;
  40        int ret;
  41
  42        /* traverse extent table, freeing each entry that is greater
  43         * than inode->i_size;
  44         */
  45        next = inode->i_ino;
  46
  47        /* only support truncate -> 0 for now */
  48        ret = -EIO;
  49        if (inode->i_size != 0)
  50                goto out;
  51
  52        bh = omfs_bread(inode->i_sb, next);
  53        if (!bh)
  54                goto out;
  55
  56        oe = (struct omfs_extent *)(&bh->b_data[OMFS_EXTENT_START]);
  57        max_extents = omfs_max_extents(sbi, OMFS_EXTENT_START);
  58
  59        for (;;) {
  60
  61                if (omfs_is_bad(sbi, (struct omfs_header *) bh->b_data, next))
  62                        goto out_brelse;
  63
  64                extent_count = be32_to_cpu(oe->e_extent_count);
  65
  66                if (extent_count > max_extents)
  67                        goto out_brelse;
  68
  69                last = next;
  70                next = be64_to_cpu(oe->e_next);
  71                entry = &oe->e_entry;
  72
  73                /* ignore last entry as it is the terminator */
  74                for (; extent_count > 1; extent_count--) {
  75                        u64 start, count;
  76                        start = be64_to_cpu(entry->e_cluster);
  77                        count = be64_to_cpu(entry->e_blocks);
  78
  79                        omfs_clear_range(inode->i_sb, start, (int) count);
  80                        entry++;
  81                }
  82                omfs_make_empty_table(bh, (char *) oe - bh->b_data);
  83                mark_buffer_dirty(bh);
  84                brelse(bh);
  85
  86                if (last != inode->i_ino)
  87                        omfs_clear_range(inode->i_sb, last, sbi->s_mirrors);
  88
  89                if (next == ~0)
  90                        break;
  91
  92                bh = omfs_bread(inode->i_sb, next);
  93                if (!bh)
  94                        goto out;
  95                oe = (struct omfs_extent *) (&bh->b_data[OMFS_EXTENT_CONT]);
  96                max_extents = omfs_max_extents(sbi, OMFS_EXTENT_CONT);
  97        }
  98        ret = 0;
  99out:
 100        return ret;
 101out_brelse:
 102        brelse(bh);
 103        return ret;
 104}
 105
 106static void omfs_truncate(struct inode *inode)
 107{
 108        omfs_shrink_inode(inode);
 109        mark_inode_dirty(inode);
 110}
 111
 112/*
 113 * Add new blocks to the current extent, or create new entries/continuations
 114 * as necessary.
 115 */
 116static int omfs_grow_extent(struct inode *inode, struct omfs_extent *oe,
 117                        u64 *ret_block)
 118{
 119        struct omfs_extent_entry *terminator;
 120        struct omfs_extent_entry *entry = &oe->e_entry;
 121        struct omfs_sb_info *sbi = OMFS_SB(inode->i_sb);
 122        u32 extent_count = be32_to_cpu(oe->e_extent_count);
 123        u64 new_block = 0;
 124        u32 max_count;
 125        int new_count;
 126        int ret = 0;
 127
 128        /* reached the end of the extent table with no blocks mapped.
 129         * there are three possibilities for adding: grow last extent,
 130         * add a new extent to the current extent table, and add a
 131         * continuation inode.  in last two cases need an allocator for
 132         * sbi->s_cluster_size
 133         */
 134
 135        /* TODO: handle holes */
 136
 137        /* should always have a terminator */
 138        if (extent_count < 1)
 139                return -EIO;
 140
 141        /* trivially grow current extent, if next block is not taken */
 142        terminator = entry + extent_count - 1;
 143        if (extent_count > 1) {
 144                entry = terminator-1;
 145                new_block = be64_to_cpu(entry->e_cluster) +
 146                        be64_to_cpu(entry->e_blocks);
 147
 148                if (omfs_allocate_block(inode->i_sb, new_block)) {
 149                        entry->e_blocks =
 150                                cpu_to_be64(be64_to_cpu(entry->e_blocks) + 1);
 151                        terminator->e_blocks = ~(cpu_to_be64(
 152                                be64_to_cpu(~terminator->e_blocks) + 1));
 153                        goto out;
 154                }
 155        }
 156        max_count = omfs_max_extents(sbi, OMFS_EXTENT_START);
 157
 158        /* TODO: add a continuation block here */
 159        if (be32_to_cpu(oe->e_extent_count) > max_count-1)
 160                return -EIO;
 161
 162        /* try to allocate a new cluster */
 163        ret = omfs_allocate_range(inode->i_sb, 1, sbi->s_clustersize,
 164                &new_block, &new_count);
 165        if (ret)
 166                goto out_fail;
 167
 168        /* copy terminator down an entry */
 169        entry = terminator;
 170        terminator++;
 171        memcpy(terminator, entry, sizeof(struct omfs_extent_entry));
 172
 173        entry->e_cluster = cpu_to_be64(new_block);
 174        entry->e_blocks = cpu_to_be64((u64) new_count);
 175
 176        terminator->e_blocks = ~(cpu_to_be64(
 177                be64_to_cpu(~terminator->e_blocks) + (u64) new_count));
 178
 179        /* write in new entry */
 180        oe->e_extent_count = cpu_to_be32(1 + be32_to_cpu(oe->e_extent_count));
 181
 182out:
 183        *ret_block = new_block;
 184out_fail:
 185        return ret;
 186}
 187
 188/*
 189 * Scans across the directory table for a given file block number.
 190 * If block not found, return 0.
 191 */
 192static sector_t find_block(struct inode *inode, struct omfs_extent_entry *ent,
 193                        sector_t block, int count, int *left)
 194{
 195        /* count > 1 because of terminator */
 196        sector_t searched = 0;
 197        for (; count > 1; count--) {
 198                int numblocks = clus_to_blk(OMFS_SB(inode->i_sb),
 199                        be64_to_cpu(ent->e_blocks));
 200
 201                if (block >= searched  &&
 202                    block < searched + numblocks) {
 203                        /*
 204                         * found it at cluster + (block - searched)
 205                         * numblocks - (block - searched) is remainder
 206                         */
 207                        *left = numblocks - (block - searched);
 208                        return clus_to_blk(OMFS_SB(inode->i_sb),
 209                                be64_to_cpu(ent->e_cluster)) +
 210                                block - searched;
 211                }
 212                searched += numblocks;
 213                ent++;
 214        }
 215        return 0;
 216}
 217
 218static int omfs_get_block(struct inode *inode, sector_t block,
 219                          struct buffer_head *bh_result, int create)
 220{
 221        struct buffer_head *bh;
 222        sector_t next, offset;
 223        int ret;
 224        u64 uninitialized_var(new_block);
 225        u32 max_extents;
 226        int extent_count;
 227        struct omfs_extent *oe;
 228        struct omfs_extent_entry *entry;
 229        struct omfs_sb_info *sbi = OMFS_SB(inode->i_sb);
 230        int max_blocks = bh_result->b_size >> inode->i_blkbits;
 231        int remain;
 232
 233        ret = -EIO;
 234        bh = omfs_bread(inode->i_sb, inode->i_ino);
 235        if (!bh)
 236                goto out;
 237
 238        oe = (struct omfs_extent *)(&bh->b_data[OMFS_EXTENT_START]);
 239        max_extents = omfs_max_extents(sbi, OMFS_EXTENT_START);
 240        next = inode->i_ino;
 241
 242        for (;;) {
 243
 244                if (omfs_is_bad(sbi, (struct omfs_header *) bh->b_data, next))
 245                        goto out_brelse;
 246
 247                extent_count = be32_to_cpu(oe->e_extent_count);
 248                next = be64_to_cpu(oe->e_next);
 249                entry = &oe->e_entry;
 250
 251                if (extent_count > max_extents)
 252                        goto out_brelse;
 253
 254                offset = find_block(inode, entry, block, extent_count, &remain);
 255                if (offset > 0) {
 256                        ret = 0;
 257                        map_bh(bh_result, inode->i_sb, offset);
 258                        if (remain > max_blocks)
 259                                remain = max_blocks;
 260                        bh_result->b_size = (remain << inode->i_blkbits);
 261                        goto out_brelse;
 262                }
 263                if (next == ~0)
 264                        break;
 265
 266                brelse(bh);
 267                bh = omfs_bread(inode->i_sb, next);
 268                if (!bh)
 269                        goto out;
 270                oe = (struct omfs_extent *) (&bh->b_data[OMFS_EXTENT_CONT]);
 271                max_extents = omfs_max_extents(sbi, OMFS_EXTENT_CONT);
 272        }
 273        if (create) {
 274                ret = omfs_grow_extent(inode, oe, &new_block);
 275                if (ret == 0) {
 276                        mark_buffer_dirty(bh);
 277                        mark_inode_dirty(inode);
 278                        map_bh(bh_result, inode->i_sb,
 279                                        clus_to_blk(sbi, new_block));
 280                }
 281        }
 282out_brelse:
 283        brelse(bh);
 284out:
 285        return ret;
 286}
 287
 288static int omfs_readpage(struct file *file, struct page *page)
 289{
 290        return block_read_full_page(page, omfs_get_block);
 291}
 292
 293static int omfs_readpages(struct file *file, struct address_space *mapping,
 294                struct list_head *pages, unsigned nr_pages)
 295{
 296        return mpage_readpages(mapping, pages, nr_pages, omfs_get_block);
 297}
 298
 299static int omfs_writepage(struct page *page, struct writeback_control *wbc)
 300{
 301        return block_write_full_page(page, omfs_get_block, wbc);
 302}
 303
 304static int
 305omfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
 306{
 307        return mpage_writepages(mapping, wbc, omfs_get_block);
 308}
 309
 310static int omfs_write_begin(struct file *file, struct address_space *mapping,
 311                        loff_t pos, unsigned len, unsigned flags,
 312                        struct page **pagep, void **fsdata)
 313{
 314        int ret;
 315
 316        ret = block_write_begin(mapping, pos, len, flags, pagep,
 317                                omfs_get_block);
 318        if (unlikely(ret)) {
 319                loff_t isize = mapping->host->i_size;
 320                if (pos + len > isize)
 321                        vmtruncate(mapping->host, isize);
 322        }
 323
 324        return ret;
 325}
 326
 327static sector_t omfs_bmap(struct address_space *mapping, sector_t block)
 328{
 329        return generic_block_bmap(mapping, block, omfs_get_block);
 330}
 331
 332const struct file_operations omfs_file_operations = {
 333        .llseek = generic_file_llseek,
 334        .read = do_sync_read,
 335        .write = do_sync_write,
 336        .aio_read = generic_file_aio_read,
 337        .aio_write = generic_file_aio_write,
 338        .mmap = generic_file_mmap,
 339        .fsync = generic_file_fsync,
 340        .splice_read = generic_file_splice_read,
 341};
 342
 343static int omfs_setattr(struct dentry *dentry, struct iattr *attr)
 344{
 345        struct inode *inode = dentry->d_inode;
 346        int error;
 347
 348        error = inode_change_ok(inode, attr);
 349        if (error)
 350                return error;
 351
 352        if ((attr->ia_valid & ATTR_SIZE) &&
 353            attr->ia_size != i_size_read(inode)) {
 354                error = vmtruncate(inode, attr->ia_size);
 355                if (error)
 356                        return error;
 357        }
 358
 359        setattr_copy(inode, attr);
 360        mark_inode_dirty(inode);
 361        return 0;
 362}
 363
 364const struct inode_operations omfs_file_inops = {
 365        .setattr = omfs_setattr,
 366        .truncate = omfs_truncate
 367};
 368
 369const struct address_space_operations omfs_aops = {
 370        .readpage = omfs_readpage,
 371        .readpages = omfs_readpages,
 372        .writepage = omfs_writepage,
 373        .writepages = omfs_writepages,
 374        .write_begin = omfs_write_begin,
 375        .write_end = generic_write_end,
 376        .bmap = omfs_bmap,
 377};
 378
 379