OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [affs/] [file.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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
 
37
static int affs_grow_extcache(struct inode *inode, u32 lc_idx);
38
static struct buffer_head *affs_alloc_extblock(struct inode *inode, struct buffer_head *bh, u32 ext);
39
static inline struct buffer_head *affs_get_extblock(struct inode *inode, u32 ext);
40
static struct buffer_head *affs_get_extblock_slow(struct inode *inode, u32 ext);
41
static int affs_get_block(struct inode *inode, long block, struct buffer_head *bh_result, int create);
42
 
43
static ssize_t affs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos);
44
static int affs_file_open(struct inode *inode, struct file *filp);
45
static int affs_file_release(struct inode *inode, struct file *filp);
46
 
47
struct 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
 
57
struct inode_operations affs_file_inode_operations = {
58
        truncate:       affs_truncate,
59
        setattr:        affs_notify_change,
60
};
61
 
62
static int
63
affs_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
 
72
static int
73
affs_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
 
85
static int
86
affs_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
 
150
err:
151
        // lock cache
152
        return -EIO;
153
}
154
 
155
static struct buffer_head *
156
affs_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
 
193
static inline struct buffer_head *
194
affs_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
 
207
static struct buffer_head *
208
affs_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
 
254
again:
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];
294
find_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
 
312
read_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
 
320
store_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
 
329
err_bread:
330
        affs_brelse(bh);
331
        return ERR_PTR(-EIO);
332
}
333
 
334
static int
335
affs_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
 
395
err_small:
396
        affs_error(inode->i_sb,"get_block","Block < 0");
397
        return -EIO;
398
err_big:
399
        affs_error(inode->i_sb,"get_block","strange block request %d", block);
400
        return -EIO;
401
err_ext:
402
        // unlock cache
403
        affs_unlock_ext(inode);
404
        return PTR_ERR(ext_bh);
405
err_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
 
413
static int affs_writepage(struct page *page)
414
{
415
        return block_write_full_page(page, affs_get_block);
416
}
417
static int affs_readpage(struct file *file, struct page *page)
418
{
419
        return block_read_full_page(page, affs_get_block);
420
}
421
static 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
}
426
static int _affs_bmap(struct address_space *mapping, long block)
427
{
428
        return generic_block_bmap(mapping,block,affs_get_block);
429
}
430
struct 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
 
439
static inline struct buffer_head *
440
affs_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
 
458
static inline struct buffer_head *
459
affs_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
 
477
static inline struct buffer_head *
478
affs_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
 
496
static ssize_t
497
affs_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
 
510
static int
511
affs_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
 
545
static int
546
affs_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
 
610
out:
611
        inode->i_size = AFFS_INODE->mmu_private = size;
612
        return PTR_ERR(bh);
613
}
614
 
615
static int
616
affs_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
 
636
static 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
 
673
static 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
 
775
done:
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
 
783
out:
784
        bh = prev_bh;
785
        if (!written)
786
                written = PTR_ERR(bh);
787
        goto done;
788
}
789
 
790
struct 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
 
800
void
801
affs_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
 
815
void
816
affs_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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.