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