import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / fs / bfs / inode.c
1 /*
2  *      fs/bfs/inode.c
3  *      BFS superblock and inode operations.
4  *      Copyright (C) 1999,2000 Tigran Aivazian <tigran@veritas.com>
5  *      From fs/minix, Copyright (C) 1991, 1992 Linus Torvalds.
6  */
7
8 #include <linux/module.h>
9 #include <linux/mm.h>
10 #include <linux/slab.h>
11 #include <linux/init.h>
12 #include <linux/locks.h>
13 #include <linux/bfs_fs.h>
14 #include <linux/smp_lock.h>
15
16 #include <asm/uaccess.h>
17
18 #include "bfs_defs.h"
19
20 MODULE_AUTHOR("Tigran A. Aivazian <tigran@veritas.com>");
21 MODULE_DESCRIPTION("SCO UnixWare BFS filesystem for Linux");
22 MODULE_LICENSE("GPL");
23 EXPORT_NO_SYMBOLS;
24
25 #undef DEBUG
26
27 #ifdef DEBUG
28 #define dprintf(x...)   printf(x)
29 #else
30 #define dprintf(x...)
31 #endif
32
33 void dump_imap(const char *prefix, struct super_block * s);
34
35 static void bfs_read_inode(struct inode * inode)
36 {
37         unsigned long ino = inode->i_ino;
38         kdev_t dev = inode->i_dev;
39         struct bfs_inode * di;
40         struct buffer_head * bh;
41         int block, off;
42
43         if (ino < BFS_ROOT_INO || ino > inode->i_sb->su_lasti) {
44                 printf("Bad inode number %s:%08lx\n", bdevname(dev), ino);
45                 make_bad_inode(inode);
46                 return;
47         }
48
49         block = (ino - BFS_ROOT_INO)/BFS_INODES_PER_BLOCK + 1;
50         bh = sb_bread(inode->i_sb, block);
51         if (!bh) {
52                 printf("Unable to read inode %s:%08lx\n", bdevname(dev), ino);
53                 make_bad_inode(inode);
54                 return;
55         }
56
57         off = (ino - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK;
58         di = (struct bfs_inode *)bh->b_data + off;
59
60         inode->i_mode = 0x0000FFFF & di->i_mode;
61         if (di->i_vtype == BFS_VDIR) {
62                 inode->i_mode |= S_IFDIR;
63                 inode->i_op = &bfs_dir_inops;
64                 inode->i_fop = &bfs_dir_operations;
65         } else if (di->i_vtype == BFS_VREG) {
66                 inode->i_mode |= S_IFREG;
67                 inode->i_op = &bfs_file_inops;
68                 inode->i_fop = &bfs_file_operations;
69                 inode->i_mapping->a_ops = &bfs_aops;
70         }
71
72         inode->i_uid = di->i_uid;
73         inode->i_gid = di->i_gid;
74         inode->i_nlink = di->i_nlink;
75         inode->i_size = BFS_FILESIZE(di);
76         inode->i_blocks = BFS_FILEBLOCKS(di);
77         inode->i_blksize = PAGE_SIZE;
78         inode->i_atime = di->i_atime;
79         inode->i_mtime = di->i_mtime;
80         inode->i_ctime = di->i_ctime;
81         inode->iu_dsk_ino = di->i_ino; /* can be 0 so we store a copy */
82         inode->iu_sblock = di->i_sblock;
83         inode->iu_eblock = di->i_eblock;
84
85         brelse(bh);
86 }
87
88 static void bfs_write_inode(struct inode * inode, int unused)
89 {
90         unsigned long ino = inode->i_ino;
91         kdev_t dev = inode->i_dev;
92         struct bfs_inode * di;
93         struct buffer_head * bh;
94         int block, off;
95
96         if (ino < BFS_ROOT_INO || ino > inode->i_sb->su_lasti) {
97                 printf("Bad inode number %s:%08lx\n", bdevname(dev), ino);
98                 return;
99         }
100
101         lock_kernel();
102         block = (ino - BFS_ROOT_INO)/BFS_INODES_PER_BLOCK + 1;
103         bh = sb_bread(inode->i_sb, block);
104         if (!bh) {
105                 printf("Unable to read inode %s:%08lx\n", bdevname(dev), ino);
106                 unlock_kernel();
107                 return;
108         }
109
110         off = (ino - BFS_ROOT_INO)%BFS_INODES_PER_BLOCK;
111         di = (struct bfs_inode *)bh->b_data + off;
112
113         if (inode->i_ino == BFS_ROOT_INO)
114                 di->i_vtype = BFS_VDIR;
115         else
116                 di->i_vtype = BFS_VREG;
117
118         di->i_ino = inode->i_ino;
119         di->i_mode = inode->i_mode;
120         di->i_uid = inode->i_uid;
121         di->i_gid = inode->i_gid;
122         di->i_nlink = inode->i_nlink;
123         di->i_atime = inode->i_atime;
124         di->i_mtime = inode->i_mtime;
125         di->i_ctime = inode->i_ctime;
126         di->i_sblock = inode->iu_sblock;
127         di->i_eblock = inode->iu_eblock;
128         di->i_eoffset = di->i_sblock * BFS_BSIZE + inode->i_size - 1;
129
130         mark_buffer_dirty(bh);
131         brelse(bh);
132         unlock_kernel();
133 }
134
135 static void bfs_delete_inode(struct inode * inode)
136 {
137         unsigned long ino = inode->i_ino;
138         kdev_t dev = inode->i_dev;
139         struct bfs_inode * di;
140         struct buffer_head * bh;
141         int block, off;
142         struct super_block * s = inode->i_sb;
143
144         dprintf("ino=%08lx\n", inode->i_ino);
145
146         if (inode->i_ino < BFS_ROOT_INO || inode->i_ino > inode->i_sb->su_lasti) {
147                 printf("invalid ino=%08lx\n", inode->i_ino);
148                 return;
149         }
150         
151         inode->i_size = 0;
152         inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
153         lock_kernel();
154         mark_inode_dirty(inode);
155         block = (ino - BFS_ROOT_INO)/BFS_INODES_PER_BLOCK + 1;
156         bh = sb_bread(s, block);
157         if (!bh) {
158                 printf("Unable to read inode %s:%08lx\n", bdevname(dev), ino);
159                 unlock_kernel();
160                 return;
161         }
162         off = (ino - BFS_ROOT_INO)%BFS_INODES_PER_BLOCK;
163         di = (struct bfs_inode *)bh->b_data + off;
164         if (di->i_ino) {
165                 s->su_freeb += BFS_FILEBLOCKS(di);
166                 s->su_freei++;
167                 clear_bit(di->i_ino, s->su_imap);
168                 dump_imap("delete_inode", s);
169         }
170         di->i_ino = 0;
171         di->i_sblock = 0;
172         mark_buffer_dirty(bh);
173         brelse(bh);
174
175         /* if this was the last file, make the previous 
176            block "last files last block" even if there is no real file there,
177            saves us 1 gap */
178         if (s->su_lf_eblk == inode->iu_eblock) {
179                 s->su_lf_eblk = inode->iu_sblock - 1;
180                 mark_buffer_dirty(s->su_sbh);
181         }
182         unlock_kernel();
183         clear_inode(inode);
184 }
185
186 static void bfs_put_super(struct super_block *s)
187 {
188         brelse(s->su_sbh);
189         kfree(s->su_imap);
190 }
191
192 static int bfs_statfs(struct super_block *s, struct statfs *buf)
193 {
194         buf->f_type = BFS_MAGIC;
195         buf->f_bsize = s->s_blocksize;
196         buf->f_blocks = s->su_blocks;
197         buf->f_bfree = buf->f_bavail = s->su_freeb;
198         buf->f_files = s->su_lasti + 1 - BFS_ROOT_INO;
199         buf->f_ffree = s->su_freei;
200         buf->f_fsid.val[0] = kdev_t_to_nr(s->s_dev);
201         buf->f_namelen = BFS_NAMELEN;
202         return 0;
203 }
204
205 static void bfs_write_super(struct super_block *s)
206 {
207         if (!(s->s_flags & MS_RDONLY))
208                 mark_buffer_dirty(s->su_sbh);
209         s->s_dirt = 0;
210 }
211
212 static struct super_operations bfs_sops = {
213         read_inode:     bfs_read_inode,
214         write_inode:    bfs_write_inode,
215         delete_inode:   bfs_delete_inode,
216         put_super:      bfs_put_super,
217         write_super:    bfs_write_super,
218         statfs:         bfs_statfs,
219 };
220
221 void dump_imap(const char *prefix, struct super_block * s)
222 {
223 #if 0
224         int i;
225         char *tmpbuf = (char *)get_free_page(GFP_KERNEL);
226
227         if (!tmpbuf)
228                 return;
229         for (i=s->su_lasti; i>=0; i--) {
230                 if (i>PAGE_SIZE-100) break;
231                 if (test_bit(i, s->su_imap))
232                         strcat(tmpbuf, "1");
233                 else
234                         strcat(tmpbuf, "0");
235         }
236         printk(KERN_ERR "BFS-fs: %s: lasti=%08lx <%s>\n", prefix, s->su_lasti, tmpbuf);
237         free_page((unsigned long)tmpbuf);
238 #endif
239 }
240
241 static struct super_block * bfs_read_super(struct super_block * s, 
242         void * data, int silent)
243 {
244         kdev_t dev;
245         struct buffer_head * bh;
246         struct bfs_super_block * bfs_sb;
247         struct inode * inode;
248         int i, imap_len;
249
250         dev = s->s_dev;
251         set_blocksize(dev, BFS_BSIZE);
252         s->s_blocksize = BFS_BSIZE;
253         s->s_blocksize_bits = BFS_BSIZE_BITS;
254
255         bh = sb_bread(s, 0);
256         if(!bh)
257                 goto out;
258         bfs_sb = (struct bfs_super_block *)bh->b_data;
259         if (bfs_sb->s_magic != BFS_MAGIC) {
260                 if (!silent)
261                         printf("No BFS filesystem on %s (magic=%08x)\n", 
262                                 bdevname(dev), bfs_sb->s_magic);
263                 goto out;
264         }
265         if (BFS_UNCLEAN(bfs_sb, s) && !silent)
266                 printf("%s is unclean, continuing\n", bdevname(dev));
267
268         s->s_magic = BFS_MAGIC;
269         s->su_bfs_sb = bfs_sb;
270         s->su_sbh = bh;
271         s->su_lasti = (bfs_sb->s_start - BFS_BSIZE)/sizeof(struct bfs_inode) 
272                         + BFS_ROOT_INO - 1;
273
274         imap_len = s->su_lasti/8 + 1;
275         s->su_imap = kmalloc(imap_len, GFP_KERNEL);
276         if (!s->su_imap)
277                 goto out;
278         memset(s->su_imap, 0, imap_len);
279         for (i=0; i<BFS_ROOT_INO; i++) 
280                 set_bit(i, s->su_imap);
281
282         s->s_op = &bfs_sops;
283         inode = iget(s, BFS_ROOT_INO);
284         if (!inode) {
285                 kfree(s->su_imap);
286                 goto out;
287         }
288         s->s_root = d_alloc_root(inode);
289         if (!s->s_root) {
290                 iput(inode);
291                 kfree(s->su_imap);
292                 goto out;
293         }
294
295         s->su_blocks = (bfs_sb->s_end + 1)>>BFS_BSIZE_BITS; /* for statfs(2) */
296         s->su_freeb = (bfs_sb->s_end + 1 - bfs_sb->s_start)>>BFS_BSIZE_BITS;
297         s->su_freei = 0;
298         s->su_lf_eblk = 0;
299         s->su_lf_sblk = 0;
300         s->su_lf_ioff = 0;
301         for (i=BFS_ROOT_INO; i<=s->su_lasti; i++) {
302                 inode = iget(s,i);
303                 if (inode->iu_dsk_ino == 0)
304                         s->su_freei++;
305                 else {
306                         set_bit(i, s->su_imap);
307                         s->su_freeb -= inode->i_blocks;
308                         if (inode->iu_eblock > s->su_lf_eblk) {
309                                 s->su_lf_eblk = inode->iu_eblock;
310                                 s->su_lf_sblk = inode->iu_sblock;
311                                 s->su_lf_ioff = BFS_INO2OFF(i);
312                         }
313                 }
314                 iput(inode);
315         }
316         if (!(s->s_flags & MS_RDONLY)) {
317                 mark_buffer_dirty(bh);
318                 s->s_dirt = 1;
319         } 
320         dump_imap("read_super", s);
321         return s;
322
323 out:
324         brelse(bh);
325         return NULL;
326 }
327
328 static DECLARE_FSTYPE_DEV(bfs_fs_type, "bfs", bfs_read_super);
329
330 static int __init init_bfs_fs(void)
331 {
332         return register_filesystem(&bfs_fs_type);
333 }
334
335 static void __exit exit_bfs_fs(void)
336 {
337         unregister_filesystem(&bfs_fs_type);
338 }
339
340 module_init(init_bfs_fs)
341 module_exit(exit_bfs_fs)