import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / fs / bfs / file.c
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
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
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
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
139 static int bfs_writepage(struct page *page)
140 {
141         return block_write_full_page(page, bfs_get_block);
142 }
143
144 static int bfs_readpage(struct file *file, struct page *page)
145 {
146         return block_read_full_page(page, bfs_get_block);
147 }
148
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
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;