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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [fs/] [affs/] [file.c] - Blame information for rev 62

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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