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