1 /*
2 * fs/bfs/file.c
3 * BFS file operations.
4 * Copyright (C) 1999,2000 Tigran Aivazian <tigran@veritas.com>
5 */
6
7 #include <linux/fs.h>
8 #include <linux/locks.h>
9 #include <linux/bfs_fs.h>
10 #include <linux/smp_lock.h>
11 #include "bfs_defs.h"
12
13 #undef DEBUG
14
15 #ifdef DEBUG
16 #define dprintf(x...) printf(x)
17 #else
18 #define dprintf(x...)
19 #endif
20
21 struct file_operations bfs_file_operations = {
22 llseek: generic_file_llseek,
23 read: generic_file_read,
24 write: generic_file_write,
25 mmap: generic_file_mmap,
26 };
27
bfs_move_block(unsigned long from,unsigned long to,kdev_t dev)28 static int bfs_move_block(unsigned long from, unsigned long to, kdev_t dev)
29 {
30 struct buffer_head *bh, *new;
31
32 bh = bread(dev, from, BFS_BSIZE);
33 if (!bh)
34 return -EIO;
35 new = getblk(dev, to, BFS_BSIZE);
36 memcpy(new->b_data, bh->b_data, bh->b_size);
37 mark_buffer_dirty(new);
38 bforget(bh);
39 brelse(new);
40 return 0;
41 }
42
bfs_move_blocks(kdev_t dev,unsigned long start,unsigned long end,unsigned long where)43 static int bfs_move_blocks(kdev_t dev, unsigned long start, unsigned long end,
44 unsigned long where)
45 {
46 unsigned long i;
47
48 dprintf("%08lx-%08lx->%08lx\n", start, end, where);
49 for (i = start; i <= end; i++)
50 if(bfs_move_block(i, where + i, dev)) {
51 dprintf("failed to move block %08lx -> %08lx\n", i, where + i);
52 return -EIO;
53 }
54 return 0;
55 }
56
bfs_get_block(struct inode * inode,long block,struct buffer_head * bh_result,int create)57 static int bfs_get_block(struct inode * inode, long block,
58 struct buffer_head * bh_result, int create)
59 {
60 long phys;
61 int err;
62 struct super_block *sb = inode->i_sb;
63 struct buffer_head *sbh = sb->su_sbh;
64
65 if (block < 0 || block > sb->su_blocks)
66 return -EIO;
67
68 phys = inode->iu_sblock + block;
69 if (!create) {
70 if (phys <= inode->iu_eblock) {
71 dprintf("c=%d, b=%08lx, phys=%08lx (granted)\n", create, block, phys);
72 bh_result->b_dev = inode->i_dev;
73 bh_result->b_blocknr = phys;
74 bh_result->b_state |= (1UL << BH_Mapped);
75 }
76 return 0;
77 }
78
79 /* if the file is not empty and the requested block is within the range
80 of blocks allocated for this file, we can grant it */
81 if (inode->i_size && phys <= inode->iu_eblock) {
82 dprintf("c=%d, b=%08lx, phys=%08lx (interim block granted)\n",
83 create, block, phys);
84 bh_result->b_dev = inode->i_dev;
85 bh_result->b_blocknr = phys;
86 bh_result->b_state |= (1UL << BH_Mapped);
87 return 0;
88 }
89
90 /* the rest has to be protected against itself */
91 lock_kernel();
92
93 /* if the last data block for this file is the last allocated block, we can
94 extend the file trivially, without moving it anywhere */
95 if (inode->iu_eblock == sb->su_lf_eblk) {
96 dprintf("c=%d, b=%08lx, phys=%08lx (simple extension)\n",
97 create, block, phys);
98 bh_result->b_dev = inode->i_dev;
99 bh_result->b_blocknr = phys;
100 bh_result->b_state |= (1UL << BH_Mapped);
101 sb->su_freeb -= phys - inode->iu_eblock;
102 sb->su_lf_eblk = inode->iu_eblock = phys;
103 mark_inode_dirty(inode);
104 mark_buffer_dirty(sbh);
105 err = 0;
106 goto out;
107 }
108
109 /* Ok, we have to move this entire file to the next free block */
110 phys = sb->su_lf_eblk + 1;
111 if (inode->iu_sblock) { /* if data starts on block 0 then there is no data */
112 err = bfs_move_blocks(inode->i_dev, inode->iu_sblock,
113 inode->iu_eblock, phys);
114 if (err) {
115 dprintf("failed to move ino=%08lx -> fs corruption\n", inode->i_ino);
116 goto out;
117 }
118 } else
119 err = 0;
120
121 dprintf("c=%d, b=%08lx, phys=%08lx (moved)\n", create, block, phys);
122 inode->iu_sblock = phys;
123 phys += block;
124 sb->su_lf_eblk = inode->iu_eblock = phys;
125
126 /* this assumes nothing can write the inode back while we are here
127 * and thus update inode->i_blocks! (XXX)*/
128 sb->su_freeb -= inode->iu_eblock - inode->iu_sblock + 1 - inode->i_blocks;
129 mark_inode_dirty(inode);
130 mark_buffer_dirty(sbh);
131 bh_result->b_dev = inode->i_dev;
132 bh_result->b_blocknr = phys;
133 bh_result->b_state |= (1UL << BH_Mapped);
134 out:
135 unlock_kernel();
136 return err;
137 }
138
bfs_writepage(struct page * page)139 static int bfs_writepage(struct page *page)
140 {
141 return block_write_full_page(page, bfs_get_block);
142 }
143
bfs_readpage(struct file * file,struct page * page)144 static int bfs_readpage(struct file *file, struct page *page)
145 {
146 return block_read_full_page(page, bfs_get_block);
147 }
148
bfs_prepare_write(struct file * file,struct page * page,unsigned from,unsigned to)149 static int bfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
150 {
151 return block_prepare_write(page, from, to, bfs_get_block);
152 }
153
bfs_bmap(struct address_space * mapping,long block)154 static int bfs_bmap(struct address_space *mapping, long block)
155 {
156 return generic_block_bmap(mapping, block, bfs_get_block);
157 }
158
159 struct address_space_operations bfs_aops = {
160 readpage: bfs_readpage,
161 writepage: bfs_writepage,
162 sync_page: block_sync_page,
163 prepare_write: bfs_prepare_write,
164 commit_write: generic_commit_write,
165 bmap: bfs_bmap,
166 };
167
168 struct inode_operations bfs_file_inops;
169