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