linux-old/fs/affs/file.c
<<
>>
Prefs
   1/*
   2 *  linux/fs/affs/file.c
   3 *
   4 *  (c) 1996  Hans-Joachim Widmaier - Rewritten
   5 *
   6 *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
   7 *
   8 *  (C) 1992  Eric Youngdale Modified for ISO 9660 filesystem.
   9 *
  10 *  (C) 1991  Linus Torvalds - minix filesystem
  11 *
  12 *  affs regular file handling primitives
  13 */
  14
  15#include <asm/div64.h>
  16#include <asm/uaccess.h>
  17#include <asm/system.h>
  18#include <linux/sched.h>
  19#include <linux/affs_fs.h>
  20#include <linux/fcntl.h>
  21#include <linux/kernel.h>
  22#include <linux/errno.h>
  23#include <linux/slab.h>
  24#include <linux/stat.h>
  25#include <linux/locks.h>
  26#include <linux/smp_lock.h>
  27#include <linux/dirent.h>
  28#include <linux/fs.h>
  29#include <linux/amigaffs.h>
  30#include <linux/mm.h>
  31#include <linux/pagemap.h>
  32
  33#if PAGE_SIZE < 4096
  34#error PAGE_SIZE must be at least 4096
  35#endif
  36
  37static int affs_grow_extcache(struct inode *inode, u32 lc_idx);
  38static struct buffer_head *affs_alloc_extblock(struct inode *inode, struct buffer_head *bh, u32 ext);
  39static inline struct buffer_head *affs_get_extblock(struct inode *inode, u32 ext);
  40static struct buffer_head *affs_get_extblock_slow(struct inode *inode, u32 ext);
  41static int affs_get_block(struct inode *inode, long block, struct buffer_head *bh_result, int create);
  42
  43static ssize_t affs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos);
  44static int affs_file_open(struct inode *inode, struct file *filp);
  45static int affs_file_release(struct inode *inode, struct file *filp);
  46
  47struct file_operations affs_file_operations = {
  48        llseek:         generic_file_llseek,
  49        read:           generic_file_read,
  50        write:          affs_file_write,
  51        mmap:           generic_file_mmap,
  52        open:           affs_file_open,
  53        release:        affs_file_release,
  54        fsync:          file_fsync,
  55};
  56
  57struct inode_operations affs_file_inode_operations = {
  58        truncate:       affs_truncate,
  59        setattr:        affs_notify_change,
  60};
  61
  62static int
  63affs_file_open(struct inode *inode, struct file *filp)
  64{
  65        if (atomic_read(&filp->f_count) != 1)
  66                return 0;
  67        pr_debug("AFFS: open(%d)\n", AFFS_INODE->i_opencnt);
  68        AFFS_INODE->i_opencnt++;
  69        return 0;
  70}
  71
  72static int
  73affs_file_release(struct inode *inode, struct file *filp)
  74{
  75        if (atomic_read(&filp->f_count) != 0)
  76                return 0;
  77        pr_debug("AFFS: release(%d)\n", AFFS_INODE->i_opencnt);
  78        AFFS_INODE->i_opencnt--;
  79        if (!AFFS_INODE->i_opencnt)
  80                affs_free_prealloc(inode);
  81
  82        return 0;
  83}
  84
  85static int
  86affs_grow_extcache(struct inode *inode, u32 lc_idx)
  87{
  88        struct super_block      *sb = inode->i_sb;
  89        struct buffer_head      *bh;
  90        u32 lc_max;
  91        int i, j, key;
  92
  93        if (!AFFS_INODE->i_lc) {
  94                char *ptr = (char *)get_zeroed_page(GFP_NOFS);
  95                if (!ptr)
  96                        return -ENOMEM;
  97                AFFS_INODE->i_lc = (u32 *)ptr;
  98                AFFS_INODE->i_ac = (struct affs_ext_key *)(ptr + AFFS_CACHE_SIZE / 2);
  99        }
 100
 101        lc_max = AFFS_LC_SIZE << AFFS_INODE->i_lc_shift;
 102
 103        if (AFFS_INODE->i_extcnt > lc_max) {
 104                u32 lc_shift, lc_mask, tmp, off;
 105
 106                /* need to recalculate linear cache, start from old size */
 107                lc_shift = AFFS_INODE->i_lc_shift;
 108                tmp = (AFFS_INODE->i_extcnt / AFFS_LC_SIZE) >> lc_shift;
 109                for (; tmp; tmp >>= 1)
 110                        lc_shift++;
 111                lc_mask = (1 << lc_shift) - 1;
 112
 113                /* fix idx and old size to new shift */
 114                lc_idx >>= (lc_shift - AFFS_INODE->i_lc_shift);
 115                AFFS_INODE->i_lc_size >>= (lc_shift - AFFS_INODE->i_lc_shift);
 116
 117                /* first shrink old cache to make more space */
 118                off = 1 << (lc_shift - AFFS_INODE->i_lc_shift);
 119                for (i = 1, j = off; j < AFFS_LC_SIZE; i++, j += off)
 120                        AFFS_INODE->i_ac[i] = AFFS_INODE->i_ac[j];
 121
 122                AFFS_INODE->i_lc_shift = lc_shift;
 123                AFFS_INODE->i_lc_mask = lc_mask;
 124        }
 125
 126        /* fill cache to the needed index */
 127        i = AFFS_INODE->i_lc_size;
 128        AFFS_INODE->i_lc_size = lc_idx + 1;
 129        for (; i <= lc_idx; i++) {
 130                if (!i) {
 131                        AFFS_INODE->i_lc[0] = inode->i_ino;
 132                        continue;
 133                }
 134                key = AFFS_INODE->i_lc[i - 1];
 135                j = AFFS_INODE->i_lc_mask + 1;
 136                // unlock cache
 137                for (; j > 0; j--) {
 138                        bh = affs_bread(sb, key);
 139                        if (!bh)
 140                                goto err;
 141                        key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);
 142                        affs_brelse(bh);
 143                }
 144                // lock cache
 145                AFFS_INODE->i_lc[i] = key;
 146        }
 147
 148        return 0;
 149
 150err:
 151        // lock cache
 152        return -EIO;
 153}
 154
 155static struct buffer_head *
 156affs_alloc_extblock(struct inode *inode, struct buffer_head *bh, u32 ext)
 157{
 158        struct super_block *sb = inode->i_sb;
 159        struct buffer_head *new_bh;
 160        u32 blocknr, tmp;
 161
 162        blocknr = affs_alloc_block(inode, bh->b_blocknr);
 163        if (!blocknr)
 164                return ERR_PTR(-ENOSPC);
 165
 166        new_bh = affs_getzeroblk(sb, blocknr);
 167        if (!new_bh) {
 168                affs_free_block(sb, blocknr);
 169                return ERR_PTR(-EIO);
 170        }
 171
 172        AFFS_HEAD(new_bh)->ptype = cpu_to_be32(T_LIST);
 173        AFFS_HEAD(new_bh)->key = cpu_to_be32(blocknr);
 174        AFFS_TAIL(sb, new_bh)->stype = cpu_to_be32(ST_FILE);
 175        AFFS_TAIL(sb, new_bh)->parent = cpu_to_be32(inode->i_ino);
 176        affs_fix_checksum(sb, new_bh);
 177
 178        mark_buffer_dirty_inode(new_bh, inode);
 179
 180        tmp = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);
 181        if (tmp)
 182                affs_warning(sb, "alloc_ext", "previous extension set (%x)", tmp);
 183        AFFS_TAIL(sb, bh)->extension = cpu_to_be32(blocknr);
 184        affs_adjust_checksum(bh, blocknr - tmp);
 185        mark_buffer_dirty_inode(bh, inode);
 186
 187        AFFS_INODE->i_extcnt++;
 188        mark_inode_dirty(inode);
 189
 190        return new_bh;
 191}
 192
 193static inline struct buffer_head *
 194affs_get_extblock(struct inode *inode, u32 ext)
 195{
 196        /* inline the simplest case: same extended block as last time */
 197        struct buffer_head *bh = AFFS_INODE->i_ext_bh;
 198        if (ext == AFFS_INODE->i_ext_last)
 199                atomic_inc(&bh->b_count);
 200        else
 201                /* we have to do more (not inlined) */
 202                bh = affs_get_extblock_slow(inode, ext);
 203
 204        return bh;
 205}
 206
 207static struct buffer_head *
 208affs_get_extblock_slow(struct inode *inode, u32 ext)
 209{
 210        struct super_block *sb = inode->i_sb;
 211        struct buffer_head *bh;
 212        u32 ext_key;
 213        u32 lc_idx, lc_off, ac_idx;
 214        u32 tmp, idx;
 215
 216        if (ext == AFFS_INODE->i_ext_last + 1) {
 217                /* read the next extended block from the current one */
 218                bh = AFFS_INODE->i_ext_bh;
 219                ext_key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);
 220                if (ext < AFFS_INODE->i_extcnt)
 221                        goto read_ext;
 222                if (ext > AFFS_INODE->i_extcnt)
 223                        BUG();
 224                bh = affs_alloc_extblock(inode, bh, ext);
 225                if (IS_ERR(bh))
 226                        return bh;
 227                goto store_ext;
 228        }
 229
 230        if (ext == 0) {
 231                /* we seek back to the file header block */
 232                ext_key = inode->i_ino;
 233                goto read_ext;
 234        }
 235
 236        if (ext >= AFFS_INODE->i_extcnt) {
 237                struct buffer_head *prev_bh;
 238
 239                /* allocate a new extended block */
 240                if (ext > AFFS_INODE->i_extcnt)
 241                        BUG();
 242
 243                /* get previous extended block */
 244                prev_bh = affs_get_extblock(inode, ext - 1);
 245                if (IS_ERR(prev_bh))
 246                        return prev_bh;
 247                bh = affs_alloc_extblock(inode, prev_bh, ext);
 248                affs_brelse(prev_bh);
 249                if (IS_ERR(bh))
 250                        return bh;
 251                goto store_ext;
 252        }
 253
 254again:
 255        /* check if there is an extended cache and whether it's large enough */
 256        lc_idx = ext >> AFFS_INODE->i_lc_shift;
 257        lc_off = ext & AFFS_INODE->i_lc_mask;
 258
 259        if (lc_idx >= AFFS_INODE->i_lc_size) {
 260                int err;
 261
 262                err = affs_grow_extcache(inode, lc_idx);
 263                if (err)
 264                        return ERR_PTR(err);
 265                goto again;
 266        }
 267
 268        /* every n'th key we find in the linear cache */
 269        if (!lc_off) {
 270                ext_key = AFFS_INODE->i_lc[lc_idx];
 271                goto read_ext;
 272        }
 273
 274        /* maybe it's still in the associative cache */
 275        ac_idx = (ext - lc_idx - 1) & AFFS_AC_MASK;
 276        if (AFFS_INODE->i_ac[ac_idx].ext == ext) {
 277                ext_key = AFFS_INODE->i_ac[ac_idx].key;
 278                goto read_ext;
 279        }
 280
 281        /* try to find one of the previous extended blocks */
 282        tmp = ext;
 283        idx = ac_idx;
 284        while (--tmp, --lc_off > 0) {
 285                idx = (idx - 1) & AFFS_AC_MASK;
 286                if (AFFS_INODE->i_ac[idx].ext == tmp) {
 287                        ext_key = AFFS_INODE->i_ac[idx].key;
 288                        goto find_ext;
 289                }
 290        }
 291
 292        /* fall back to the linear cache */
 293        ext_key = AFFS_INODE->i_lc[lc_idx];
 294find_ext:
 295        /* read all extended blocks until we find the one we need */
 296        //unlock cache
 297        do {
 298                bh = affs_bread(sb, ext_key);
 299                if (!bh)
 300                        goto err_bread;
 301                ext_key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);
 302                affs_brelse(bh);
 303                tmp++;
 304        } while (tmp < ext);
 305        //lock cache
 306
 307        /* store it in the associative cache */
 308        // recalculate ac_idx?
 309        AFFS_INODE->i_ac[ac_idx].ext = ext;
 310        AFFS_INODE->i_ac[ac_idx].key = ext_key;
 311
 312read_ext:
 313        /* finally read the right extended block */
 314        //unlock cache
 315        bh = affs_bread(sb, ext_key);
 316        if (!bh)
 317                goto err_bread;
 318        //lock cache
 319
 320store_ext:
 321        /* release old cached extended block and store the new one */
 322        affs_brelse(AFFS_INODE->i_ext_bh);
 323        AFFS_INODE->i_ext_last = ext;
 324        AFFS_INODE->i_ext_bh = bh;
 325        atomic_inc(&bh->b_count);
 326
 327        return bh;
 328
 329err_bread:
 330        affs_brelse(bh);
 331        return ERR_PTR(-EIO);
 332}
 333
 334static int
 335affs_get_block(struct inode *inode, long block, struct buffer_head *bh_result, int create)
 336{
 337        struct super_block      *sb = inode->i_sb;
 338        struct buffer_head      *ext_bh;
 339        u32                      ext;
 340
 341        pr_debug("AFFS: get_block(%u, %ld)\n", (u32)inode->i_ino, block);
 342
 343        if (block < 0)
 344                goto err_small;
 345
 346        if (block >= AFFS_INODE->i_blkcnt) {
 347                if (block > AFFS_INODE->i_blkcnt || !create)
 348                        goto err_big;
 349        } else
 350                create = 0;
 351
 352        //lock cache
 353        affs_lock_ext(inode);
 354
 355        ext = block / AFFS_SB->s_hashsize;
 356        block -= ext * AFFS_SB->s_hashsize;
 357        ext_bh = affs_get_extblock(inode, ext);
 358        if (IS_ERR(ext_bh))
 359                goto err_ext;
 360        bh_result->b_blocknr = be32_to_cpu(AFFS_BLOCK(sb, ext_bh, block));
 361        bh_result->b_dev = inode->i_dev;
 362        bh_result->b_state |= (1UL << BH_Mapped);
 363
 364        if (create) {
 365                u32 blocknr = affs_alloc_block(inode, ext_bh->b_blocknr);
 366                if (!blocknr)
 367                        goto err_alloc;
 368                bh_result->b_state |= (1UL << BH_New);
 369                AFFS_INODE->mmu_private += AFFS_SB->s_data_blksize;
 370                AFFS_INODE->i_blkcnt++;
 371
 372                /* store new block */
 373                if (bh_result->b_blocknr)
 374                        affs_warning(sb, "get_block", "block already set (%x)", bh_result->b_blocknr);
 375                AFFS_BLOCK(sb, ext_bh, block) = cpu_to_be32(blocknr);
 376                AFFS_HEAD(ext_bh)->block_count = cpu_to_be32(block + 1);
 377                affs_adjust_checksum(ext_bh, blocknr - bh_result->b_blocknr + 1);
 378                bh_result->b_blocknr = blocknr;
 379
 380                if (!block) {
 381                        /* insert first block into header block */
 382                        u32 tmp = be32_to_cpu(AFFS_HEAD(ext_bh)->first_data);
 383                        if (tmp)
 384                                affs_warning(sb, "get_block", "first block already set (%d)", tmp);
 385                        AFFS_HEAD(ext_bh)->first_data = cpu_to_be32(blocknr);
 386                        affs_adjust_checksum(ext_bh, blocknr - tmp);
 387                }
 388        }
 389
 390        affs_brelse(ext_bh);
 391        //unlock cache
 392        affs_unlock_ext(inode);
 393        return 0;
 394
 395err_small:
 396        affs_error(inode->i_sb,"get_block","Block < 0");
 397        return -EIO;
 398err_big:
 399        affs_error(inode->i_sb,"get_block","strange block request %d", block);
 400        return -EIO;
 401err_ext:
 402        // unlock cache
 403        affs_unlock_ext(inode);
 404        return PTR_ERR(ext_bh);
 405err_alloc:
 406        brelse(ext_bh);
 407        bh_result->b_state &= ~(1UL << BH_Mapped);
 408        // unlock cache
 409        affs_unlock_ext(inode);
 410        return -ENOSPC;
 411}
 412
 413static int affs_writepage(struct page *page)
 414{
 415        return block_write_full_page(page, affs_get_block);
 416}
 417static int affs_readpage(struct file *file, struct page *page)
 418{
 419        return block_read_full_page(page, affs_get_block);
 420}
 421static int affs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
 422{
 423        return cont_prepare_write(page, from, to, affs_get_block,
 424                &page->mapping->host->u.affs_i.mmu_private);
 425}
 426static int _affs_bmap(struct address_space *mapping, long block)
 427{
 428        return generic_block_bmap(mapping,block,affs_get_block);
 429}
 430struct address_space_operations affs_aops = {
 431        readpage: affs_readpage,
 432        writepage: affs_writepage,
 433        sync_page: block_sync_page,
 434        prepare_write: affs_prepare_write,
 435        commit_write: generic_commit_write,
 436        bmap: _affs_bmap
 437};
 438
 439static inline struct buffer_head *
 440affs_bread_ino(struct inode *inode, int block, int create)
 441{
 442        struct buffer_head *bh, tmp_bh;
 443        int err;
 444
 445        tmp_bh.b_state = 0;
 446        err = affs_get_block(inode, block, &tmp_bh, create);
 447        if (!err) {
 448                bh = affs_bread(inode->i_sb, tmp_bh.b_blocknr);
 449                if (bh) {
 450                        bh->b_state |= tmp_bh.b_state;
 451                        return bh;
 452                }
 453                err = -EIO;
 454        }
 455        return ERR_PTR(err);
 456}
 457
 458static inline struct buffer_head *
 459affs_getzeroblk_ino(struct inode *inode, int block)
 460{
 461        struct buffer_head *bh, tmp_bh;
 462        int err;
 463
 464        tmp_bh.b_state = 0;
 465        err = affs_get_block(inode, block, &tmp_bh, 1);
 466        if (!err) {
 467                bh = affs_getzeroblk(inode->i_sb, tmp_bh.b_blocknr);
 468                if (bh) {
 469                        bh->b_state |= tmp_bh.b_state;
 470                        return bh;
 471                }
 472                err = -EIO;
 473        }
 474        return ERR_PTR(err);
 475}
 476
 477static inline struct buffer_head *
 478affs_getemptyblk_ino(struct inode *inode, int block)
 479{
 480        struct buffer_head *bh, tmp_bh;
 481        int err;
 482
 483        tmp_bh.b_state = 0;
 484        err = affs_get_block(inode, block, &tmp_bh, 1);
 485        if (!err) {
 486                bh = affs_getemptyblk(inode->i_sb, tmp_bh.b_blocknr);
 487                if (bh) {
 488                        bh->b_state |= tmp_bh.b_state;
 489                        return bh;
 490                }
 491                err = -EIO;
 492        }
 493        return ERR_PTR(err);
 494}
 495
 496static ssize_t
 497affs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
 498{
 499        ssize_t retval;
 500
 501        retval = generic_file_write (file, buf, count, ppos);
 502        if (retval >0) {
 503                struct inode *inode = file->f_dentry->d_inode;
 504                inode->i_ctime = inode->i_mtime = CURRENT_TIME;
 505                mark_inode_dirty(inode);
 506        }
 507        return retval;
 508}
 509
 510static int
 511affs_do_readpage_ofs(struct file *file, struct page *page, unsigned from, unsigned to)
 512{
 513        struct inode *inode = page->mapping->host;
 514        struct super_block *sb = inode->i_sb;
 515        struct buffer_head *bh;
 516        char *data;
 517        u32 bidx, boff, bsize;
 518        u32 tmp;
 519
 520        pr_debug("AFFS: read_page(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to);
 521        if (from > to || to > PAGE_CACHE_SIZE)
 522                BUG();
 523        data = page_address(page);
 524        bsize = AFFS_SB->s_data_blksize;
 525        tmp = (page->index << PAGE_CACHE_SHIFT) + from;
 526        bidx = tmp / bsize;
 527        boff = tmp % bsize;
 528
 529        while (from < to) {
 530                bh = affs_bread_ino(inode, bidx, 0);
 531                if (IS_ERR(bh))
 532                        return PTR_ERR(bh);
 533                tmp = min(bsize - boff, to - from);
 534                if (from + tmp > to || tmp > bsize)
 535                        BUG();
 536                memcpy(data + from, AFFS_DATA(bh) + boff, tmp);
 537                affs_brelse(bh);
 538                bidx++;
 539                from += tmp;
 540                boff = 0;
 541        }
 542        return 0;
 543}
 544
 545static int
 546affs_extent_file_ofs(struct inode *inode, u32 newsize)
 547{
 548        struct super_block *sb = inode->i_sb;
 549        struct buffer_head *bh, *prev_bh;
 550        u32 bidx, boff;
 551        u32 size, bsize;
 552        u32 tmp;
 553
 554        pr_debug("AFFS: extent_file(%u, %d)\n", (u32)inode->i_ino, newsize);
 555        bsize = AFFS_SB->s_data_blksize;
 556        bh = NULL;
 557        size = AFFS_INODE->mmu_private;
 558        bidx = size / bsize;
 559        boff = size % bsize;
 560        if (boff) {
 561                bh = affs_bread_ino(inode, bidx, 0);
 562                if (IS_ERR(bh))
 563                        return PTR_ERR(bh);
 564                tmp = min(bsize - boff, newsize - size);
 565                if (boff + tmp > bsize || tmp > bsize)
 566                        BUG();
 567                memset(AFFS_DATA(bh) + boff, 0, tmp);
 568                AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp);
 569                affs_fix_checksum(sb, bh);
 570                mark_buffer_dirty_inode(bh, inode);
 571                size += tmp;
 572                bidx++;
 573        } else if (bidx) {
 574                bh = affs_bread_ino(inode, bidx - 1, 0);
 575                if (IS_ERR(bh))
 576                        return PTR_ERR(bh);
 577        }
 578
 579        while (size < newsize) {
 580                prev_bh = bh;
 581                bh = affs_getzeroblk_ino(inode, bidx);
 582                if (IS_ERR(bh))
 583                        goto out;
 584                tmp = min(bsize, newsize - size);
 585                if (tmp > bsize)
 586                        BUG();
 587                AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
 588                AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);
 589                AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
 590                AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);
 591                affs_fix_checksum(sb, bh);
 592                bh->b_state &= ~(1UL << BH_New);
 593                mark_buffer_dirty_inode(bh, inode);
 594                if (prev_bh) {
 595                        u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
 596                        if (tmp)
 597                                affs_warning(sb, "extent_file_ofs", "next block already set for %d (%d)", bidx, tmp);
 598                        AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
 599                        affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp);
 600                        mark_buffer_dirty_inode(prev_bh, inode);
 601                        affs_brelse(prev_bh);
 602                }
 603                size += bsize;
 604                bidx++;
 605        }
 606        affs_brelse(bh);
 607        inode->i_size = AFFS_INODE->mmu_private = newsize;
 608        return 0;
 609
 610out:
 611        inode->i_size = AFFS_INODE->mmu_private = size;
 612        return PTR_ERR(bh);
 613}
 614
 615static int
 616affs_readpage_ofs(struct file *file, struct page *page)
 617{
 618        struct inode *inode = page->mapping->host;
 619        u32 to;
 620        int err;
 621
 622        pr_debug("AFFS: read_page(%u, %ld)\n", (u32)inode->i_ino, page->index);
 623        to = PAGE_CACHE_SIZE;
 624        if (((page->index + 1) << PAGE_CACHE_SHIFT) > inode->i_size) {
 625                to = inode->i_size & ~PAGE_CACHE_MASK;
 626                memset(page_address(page) + to, 0, PAGE_CACHE_SIZE - to);
 627        }
 628
 629        err = affs_do_readpage_ofs(file, page, 0, to);
 630        if (!err)
 631                SetPageUptodate(page);
 632        UnlockPage(page);
 633        return err;
 634}
 635
 636static int affs_prepare_write_ofs(struct file *file, struct page *page, unsigned from, unsigned to)
 637{
 638        struct inode *inode = page->mapping->host;
 639        u32 size, offset;
 640        u32 tmp;
 641        int err = 0;
 642
 643        pr_debug("AFFS: prepare_write(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to);
 644        offset = page->index << PAGE_CACHE_SHIFT;
 645        if (offset + from > AFFS_INODE->mmu_private) {
 646                err = affs_extent_file_ofs(inode, offset + from);
 647                if (err)
 648                        return err;
 649        }
 650        size = inode->i_size;
 651
 652        if (Page_Uptodate(page))
 653                return 0;
 654
 655        if (from) {
 656                err = affs_do_readpage_ofs(file, page, 0, from);
 657                if (err)
 658                        return err;
 659        }
 660        if (to < PAGE_CACHE_SIZE) {
 661                memset(page_address(page) + to, 0, PAGE_CACHE_SIZE - to);
 662                if (size > offset + to) {
 663                        if (size < offset + PAGE_CACHE_SIZE)
 664                                tmp = size & ~PAGE_CACHE_MASK;
 665                        else
 666                                tmp = PAGE_CACHE_SIZE;
 667                        err = affs_do_readpage_ofs(file, page, to, tmp);
 668                }
 669        }
 670        return err;
 671}
 672
 673static int affs_commit_write_ofs(struct file *file, struct page *page, unsigned from, unsigned to)
 674{
 675        struct inode *inode = page->mapping->host;
 676        struct super_block *sb = inode->i_sb;
 677        struct buffer_head *bh, *prev_bh;
 678        char *data;
 679        u32 bidx, boff, bsize;
 680        u32 tmp;
 681        int written;
 682
 683        pr_debug("AFFS: commit_write(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to);
 684        bsize = AFFS_SB->s_data_blksize;
 685        data = page_address(page);
 686
 687        bh = NULL;
 688        written = 0;
 689        tmp = (page->index << PAGE_CACHE_SHIFT) + from;
 690        bidx = tmp / bsize;
 691        boff = tmp % bsize;
 692        if (boff) {
 693                bh = affs_bread_ino(inode, bidx, 0);
 694                if (IS_ERR(bh))
 695                        return PTR_ERR(bh);
 696                tmp = min(bsize - boff, to - from);
 697                if (boff + tmp > bsize || tmp > bsize)
 698                        BUG();
 699                memcpy(AFFS_DATA(bh) + boff, data + from, tmp);
 700                AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp);
 701                affs_fix_checksum(sb, bh);
 702                mark_buffer_dirty_inode(bh, inode);
 703                written += tmp;
 704                from += tmp;
 705                bidx++;
 706        } else if (bidx) {
 707                bh = affs_bread_ino(inode, bidx - 1, 0);
 708                if (IS_ERR(bh))
 709                        return PTR_ERR(bh);
 710        }
 711        while (from + bsize <= to) {
 712                prev_bh = bh;
 713                bh = affs_getemptyblk_ino(inode, bidx);
 714                if (IS_ERR(bh))
 715                        goto out;
 716                memcpy(AFFS_DATA(bh), data + from, bsize);
 717                if (bh->b_state & (1UL << BH_New)) {
 718                        AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
 719                        AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);
 720                        AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
 721                        AFFS_DATA_HEAD(bh)->size = cpu_to_be32(bsize);
 722                        AFFS_DATA_HEAD(bh)->next = 0;
 723                        bh->b_state &= ~(1UL << BH_New);
 724                        if (prev_bh) {
 725                                u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
 726                                if (tmp)
 727                                        affs_warning(sb, "commit_write_ofs", "next block already set for %d (%d)", bidx, tmp);
 728                                AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
 729                                affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp);
 730                                mark_buffer_dirty_inode(prev_bh, inode);
 731                        }
 732                }
 733                affs_brelse(prev_bh);
 734                affs_fix_checksum(sb, bh);
 735                mark_buffer_dirty_inode(bh, inode);
 736                written += bsize;
 737                from += bsize;
 738                bidx++;
 739        }
 740        if (from < to) {
 741                prev_bh = bh;
 742                bh = affs_bread_ino(inode, bidx, 1);
 743                if (IS_ERR(bh))
 744                        goto out;
 745                tmp = min(bsize, to - from);
 746                if (tmp > bsize)
 747                        BUG();
 748                memcpy(AFFS_DATA(bh), data + from, tmp);
 749                if (bh->b_state & (1UL << BH_New)) {
 750                        AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
 751                        AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);
 752                        AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
 753                        AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);
 754                        AFFS_DATA_HEAD(bh)->next = 0;
 755                        bh->b_state &= ~(1UL << BH_New);
 756                        if (prev_bh) {
 757                                u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
 758                                if (tmp)
 759                                        affs_warning(sb, "commit_write_ofs", "next block already set for %d (%d)", bidx, tmp);
 760                                AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
 761                                affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp);
 762                                mark_buffer_dirty_inode(prev_bh, inode);
 763                        }
 764                } else if (be32_to_cpu(AFFS_DATA_HEAD(bh)->size) < tmp)
 765                        AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);
 766                affs_brelse(prev_bh);
 767                affs_fix_checksum(sb, bh);
 768                mark_buffer_dirty_inode(bh, inode);
 769                written += tmp;
 770                from += tmp;
 771                bidx++;
 772        }
 773        SetPageUptodate(page);
 774
 775done:
 776        affs_brelse(bh);
 777        tmp = (page->index << PAGE_CACHE_SHIFT) + from;
 778        if (tmp > inode->i_size)
 779                inode->i_size = AFFS_INODE->mmu_private = tmp;
 780
 781        return written;
 782
 783out:
 784        bh = prev_bh;
 785        if (!written)
 786                written = PTR_ERR(bh);
 787        goto done;
 788}
 789
 790struct address_space_operations affs_aops_ofs = {
 791        readpage: affs_readpage_ofs,
 792        //writepage: affs_writepage_ofs,
 793        //sync_page: affs_sync_page_ofs,
 794        prepare_write: affs_prepare_write_ofs,
 795        commit_write: affs_commit_write_ofs
 796};
 797
 798/* Free any preallocated blocks. */
 799
 800void
 801affs_free_prealloc(struct inode *inode)
 802{
 803        struct super_block *sb = inode->i_sb;
 804
 805        pr_debug("AFFS: free_prealloc(ino=%lu)\n", inode->i_ino);
 806
 807        while (inode->u.affs_i.i_pa_cnt) {
 808                inode->u.affs_i.i_pa_cnt--;
 809                affs_free_block(sb, ++inode->u.affs_i.i_lastalloc);
 810        }
 811}
 812
 813/* Truncate (or enlarge) a file to the requested size. */
 814
 815void
 816affs_truncate(struct inode *inode)
 817{
 818        struct super_block *sb = inode->i_sb;
 819        u32 ext, ext_key;
 820        u32 last_blk, blkcnt, blk;
 821        u32 size;
 822        struct buffer_head *ext_bh;
 823        int i;
 824
 825        pr_debug("AFFS: truncate(inode=%d, oldsize=%u, newsize=%u)\n",
 826                 (u32)inode->i_ino, (u32)AFFS_INODE->mmu_private, (u32)inode->i_size);
 827
 828        last_blk = 0;
 829        ext = 0;
 830        if (inode->i_size) {
 831                last_blk = ((u32)inode->i_size - 1) / AFFS_SB->s_data_blksize;
 832                ext = last_blk / AFFS_SB->s_hashsize;
 833        }
 834
 835        if (inode->i_size > AFFS_INODE->mmu_private) {
 836                struct address_space *mapping = inode->i_mapping;
 837                struct page *page;
 838                u32 size = inode->i_size - 1;
 839                int res;
 840
 841                page = grab_cache_page(mapping, size >> PAGE_CACHE_SHIFT);
 842                if (!page)
 843                        return;
 844                size = (size & (PAGE_CACHE_SIZE - 1)) + 1;
 845                res = mapping->a_ops->prepare_write(NULL, page, size, size);
 846                if (!res)
 847                        res = mapping->a_ops->commit_write(NULL, page, size, size);
 848                UnlockPage(page);
 849                page_cache_release(page);
 850                mark_inode_dirty(inode);
 851                return;
 852        } else if (inode->i_size == AFFS_INODE->mmu_private)
 853                return;
 854
 855        // lock cache
 856        ext_bh = affs_get_extblock(inode, ext);
 857        if (IS_ERR(ext_bh)) {
 858                affs_warning(sb, "truncate", "unexpected read error for ext block %u (%d)",
 859                             ext, PTR_ERR(ext_bh));
 860                return;
 861        }
 862        if (AFFS_INODE->i_lc) {
 863                /* clear linear cache */
 864                i = (ext + 1) >> AFFS_INODE->i_lc_shift;
 865                if (AFFS_INODE->i_lc_size > i) {
 866                        AFFS_INODE->i_lc_size = i;
 867                        for (; i < AFFS_LC_SIZE; i++)
 868                                AFFS_INODE->i_lc[i] = 0;
 869                }
 870                /* clear associative cache */
 871                for (i = 0; i < AFFS_AC_SIZE; i++)
 872                        if (AFFS_INODE->i_ac[i].ext >= ext)
 873                                AFFS_INODE->i_ac[i].ext = 0;
 874        }
 875        ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension);
 876
 877        blkcnt = AFFS_INODE->i_blkcnt;
 878        i = 0;
 879        blk = last_blk;
 880        if (inode->i_size) {
 881                i = last_blk % AFFS_SB->s_hashsize + 1;
 882                blk++;
 883        } else
 884                AFFS_HEAD(ext_bh)->first_data = 0;
 885        size = AFFS_SB->s_hashsize;
 886        if (size > blkcnt - blk + i)
 887                size = blkcnt - blk + i;
 888        for (; i < size; i++, blk++) {
 889                affs_free_block(sb, be32_to_cpu(AFFS_BLOCK(sb, ext_bh, i)));
 890                AFFS_BLOCK(sb, ext_bh, i) = 0;
 891        }
 892        AFFS_TAIL(sb, ext_bh)->extension = 0;
 893        affs_fix_checksum(sb, ext_bh);
 894        mark_buffer_dirty_inode(ext_bh, inode);
 895        affs_brelse(ext_bh);
 896
 897        if (inode->i_size) {
 898                AFFS_INODE->i_blkcnt = last_blk + 1;
 899                AFFS_INODE->i_extcnt = ext + 1;
 900                if (AFFS_SB->s_flags & SF_OFS) {
 901                        struct buffer_head *bh = affs_bread_ino(inode, last_blk, 0);
 902                        u32 tmp;
 903                        if (IS_ERR(bh)) {
 904                                affs_warning(sb, "truncate", "unexpected read error for last block %u (%d)",
 905                                             last_blk, PTR_ERR(bh));
 906                                return;
 907                        }
 908                        tmp = be32_to_cpu(AFFS_DATA_HEAD(bh)->next);
 909                        AFFS_DATA_HEAD(bh)->next = 0;
 910                        affs_adjust_checksum(bh, -tmp);
 911                        affs_brelse(bh);
 912                }
 913        } else {
 914                AFFS_INODE->i_blkcnt = 0;
 915                AFFS_INODE->i_extcnt = 1;
 916        }
 917        AFFS_INODE->mmu_private = inode->i_size;
 918        // unlock cache
 919
 920        while (ext_key) {
 921                ext_bh = affs_bread(sb, ext_key);
 922                size = AFFS_SB->s_hashsize;
 923                if (size > blkcnt - blk)
 924                        size = blkcnt - blk;
 925                for (i = 0; i < size; i++, blk++)
 926                        affs_free_block(sb, be32_to_cpu(AFFS_BLOCK(sb, ext_bh, i)));
 927                affs_free_block(sb, ext_key);
 928                ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension);
 929                affs_brelse(ext_bh);
 930        }
 931        affs_free_prealloc(inode);
 932}
 933
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.