]> git.karo-electronics.de Git - linux-beck.git/blob - fs/freevxfs/vxfs_super.c
freevxfs: avoid the need for forward declaring the super operations
[linux-beck.git] / fs / freevxfs / vxfs_super.c
1 /*
2  * Copyright (c) 2000-2001 Christoph Hellwig.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions, and the following disclaimer,
10  *    without modification.
11  * 2. The name of the author may not be used to endorse or promote products
12  *    derived from this software without specific prior written permission.
13  *
14  * Alternatively, this software may be distributed under the terms of the
15  * GNU General Public License ("GPL").
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 /*
31  * Veritas filesystem driver - superblock related routines.
32  */
33 #include <linux/init.h>
34 #include <linux/module.h>
35
36 #include <linux/blkdev.h>
37 #include <linux/fs.h>
38 #include <linux/buffer_head.h>
39 #include <linux/kernel.h>
40 #include <linux/slab.h>
41 #include <linux/stat.h>
42 #include <linux/vfs.h>
43 #include <linux/mount.h>
44
45 #include "vxfs.h"
46 #include "vxfs_extern.h"
47 #include "vxfs_dir.h"
48 #include "vxfs_inode.h"
49
50
51 MODULE_AUTHOR("Christoph Hellwig");
52 MODULE_DESCRIPTION("Veritas Filesystem (VxFS) driver");
53 MODULE_LICENSE("Dual BSD/GPL");
54
55 /**
56  * vxfs_put_super - free superblock resources
57  * @sbp:        VFS superblock.
58  *
59  * Description:
60  *   vxfs_put_super frees all resources allocated for @sbp
61  *   after the last instance of the filesystem is unmounted.
62  */
63
64 static void
65 vxfs_put_super(struct super_block *sbp)
66 {
67         struct vxfs_sb_info     *infp = VXFS_SBI(sbp);
68
69         iput(infp->vsi_fship);
70         iput(infp->vsi_ilist);
71         iput(infp->vsi_stilist);
72
73         brelse(infp->vsi_bp);
74         kfree(infp);
75 }
76
77 /**
78  * vxfs_statfs - get filesystem information
79  * @dentry:     VFS dentry to locate superblock
80  * @bufp:       output buffer
81  *
82  * Description:
83  *   vxfs_statfs fills the statfs buffer @bufp with information
84  *   about the filesystem described by @dentry.
85  *
86  * Returns:
87  *   Zero.
88  *
89  * Locking:
90  *   No locks held.
91  *
92  * Notes:
93  *   This is everything but complete...
94  */
95 static int
96 vxfs_statfs(struct dentry *dentry, struct kstatfs *bufp)
97 {
98         struct vxfs_sb_info             *infp = VXFS_SBI(dentry->d_sb);
99         struct vxfs_sb *raw_sb = infp->vsi_raw;
100
101         bufp->f_type = VXFS_SUPER_MAGIC;
102         bufp->f_bsize = dentry->d_sb->s_blocksize;
103         bufp->f_blocks = fs32_to_cpu(infp, raw_sb->vs_dsize);
104         bufp->f_bfree = fs32_to_cpu(infp, raw_sb->vs_free);
105         bufp->f_bavail = 0;
106         bufp->f_files = 0;
107         bufp->f_ffree = fs32_to_cpu(infp, raw_sb->vs_ifree);
108         bufp->f_namelen = VXFS_NAMELEN;
109
110         return 0;
111 }
112
113 static int vxfs_remount(struct super_block *sb, int *flags, char *data)
114 {
115         sync_filesystem(sb);
116         *flags |= MS_RDONLY;
117         return 0;
118 }
119
120 static const struct super_operations vxfs_super_ops = {
121         .evict_inode            = vxfs_evict_inode,
122         .put_super              = vxfs_put_super,
123         .statfs                 = vxfs_statfs,
124         .remount_fs             = vxfs_remount,
125 };
126
127 static int vxfs_try_sb_magic(struct super_block *sbp, int silent,
128                 unsigned blk, __fs32 magic)
129 {
130         struct buffer_head *bp;
131         struct vxfs_sb *rsbp;
132         struct vxfs_sb_info *infp = VXFS_SBI(sbp);
133         int rc = -ENOMEM;
134
135         bp = sb_bread(sbp, blk);
136         do {
137                 if (!bp || !buffer_mapped(bp)) {
138                         if (!silent) {
139                                 printk(KERN_WARNING
140                                         "vxfs: unable to read disk superblock at %u\n",
141                                         blk);
142                         }
143                         break;
144                 }
145
146                 rc = -EINVAL;
147                 rsbp = (struct vxfs_sb *)bp->b_data;
148                 if (rsbp->vs_magic != magic) {
149                         if (!silent)
150                                 printk(KERN_NOTICE
151                                         "vxfs: WRONG superblock magic %08x at %u\n",
152                                         rsbp->vs_magic, blk);
153                         break;
154                 }
155
156                 rc = 0;
157                 infp->vsi_raw = rsbp;
158                 infp->vsi_bp = bp;
159         } while (0);
160
161         if (rc) {
162                 infp->vsi_raw = NULL;
163                 infp->vsi_bp = NULL;
164                 brelse(bp);
165         }
166
167         return rc;
168 }
169
170 /**
171  * vxfs_read_super - read superblock into memory and initialize filesystem
172  * @sbp:                VFS superblock (to fill)
173  * @dp:                 fs private mount data
174  * @silent:             do not complain loudly when sth is wrong
175  *
176  * Description:
177  *   We are called on the first mount of a filesystem to read the
178  *   superblock into memory and do some basic setup.
179  *
180  * Returns:
181  *   The superblock on success, else %NULL.
182  *
183  * Locking:
184  *   We are under @sbp->s_lock.
185  */
186 static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
187 {
188         struct vxfs_sb_info     *infp;
189         struct vxfs_sb          *rsbp;
190         u_long                  bsize;
191         struct inode *root;
192         int ret = -EINVAL;
193         u32 j;
194
195         sbp->s_flags |= MS_RDONLY;
196
197         infp = kzalloc(sizeof(*infp), GFP_KERNEL);
198         if (!infp) {
199                 printk(KERN_WARNING "vxfs: unable to allocate incore superblock\n");
200                 return -ENOMEM;
201         }
202
203         bsize = sb_min_blocksize(sbp, BLOCK_SIZE);
204         if (!bsize) {
205                 printk(KERN_WARNING "vxfs: unable to set blocksize\n");
206                 goto out;
207         }
208
209         sbp->s_fs_info = infp;
210
211         if (!vxfs_try_sb_magic(sbp, silent, 1,
212                         (__force __fs32)cpu_to_le32(VXFS_SUPER_MAGIC))) {
213                 /* Unixware, x86 */
214                 infp->byte_order = VXFS_BO_LE;
215         } else if (!vxfs_try_sb_magic(sbp, silent, 8,
216                         (__force __fs32)cpu_to_be32(VXFS_SUPER_MAGIC))) {
217                 /* HP-UX, parisc */
218                 infp->byte_order = VXFS_BO_BE;
219         } else {
220                 if (!silent)
221                         printk(KERN_NOTICE "vxfs: can't find superblock.\n");
222                 goto out;
223         }
224
225         rsbp = infp->vsi_raw;
226         j = fs32_to_cpu(infp, rsbp->vs_version);
227         if ((j < 2 || j > 4) && !silent) {
228                 printk(KERN_NOTICE "vxfs: unsupported VxFS version (%d)\n", j);
229                 goto out;
230         }
231
232 #ifdef DIAGNOSTIC
233         printk(KERN_DEBUG "vxfs: supported VxFS version (%d)\n", j);
234         printk(KERN_DEBUG "vxfs: blocksize: %d\n",
235                 fs32_to_cpu(infp, rsbp->vs_bsize));
236 #endif
237
238         sbp->s_magic = fs32_to_cpu(infp, rsbp->vs_magic);
239
240         infp->vsi_oltext = fs32_to_cpu(infp, rsbp->vs_oltext[0]);
241         infp->vsi_oltsize = fs32_to_cpu(infp, rsbp->vs_oltsize);
242
243         j = fs32_to_cpu(infp, rsbp->vs_bsize);
244         if (!sb_set_blocksize(sbp, j)) {
245                 printk(KERN_WARNING "vxfs: unable to set final block size\n");
246                 goto out;
247         }
248
249         if (vxfs_read_olt(sbp, bsize)) {
250                 printk(KERN_WARNING "vxfs: unable to read olt\n");
251                 goto out;
252         }
253
254         if (vxfs_read_fshead(sbp)) {
255                 printk(KERN_WARNING "vxfs: unable to read fshead\n");
256                 goto out;
257         }
258
259         sbp->s_op = &vxfs_super_ops;
260         root = vxfs_iget(sbp, VXFS_ROOT_INO);
261         if (IS_ERR(root)) {
262                 ret = PTR_ERR(root);
263                 goto out;
264         }
265         sbp->s_root = d_make_root(root);
266         if (!sbp->s_root) {
267                 printk(KERN_WARNING "vxfs: unable to get root dentry.\n");
268                 goto out_free_ilist;
269         }
270
271         return 0;
272         
273 out_free_ilist:
274         iput(infp->vsi_fship);
275         iput(infp->vsi_ilist);
276         iput(infp->vsi_stilist);
277 out:
278         brelse(infp->vsi_bp);
279         kfree(infp);
280         return ret;
281 }
282
283 /*
284  * The usual module blurb.
285  */
286 static struct dentry *vxfs_mount(struct file_system_type *fs_type,
287         int flags, const char *dev_name, void *data)
288 {
289         return mount_bdev(fs_type, flags, dev_name, data, vxfs_fill_super);
290 }
291
292 static struct file_system_type vxfs_fs_type = {
293         .owner          = THIS_MODULE,
294         .name           = "vxfs",
295         .mount          = vxfs_mount,
296         .kill_sb        = kill_block_super,
297         .fs_flags       = FS_REQUIRES_DEV,
298 };
299 MODULE_ALIAS_FS("vxfs"); /* makes mount -t vxfs autoload the module */
300 MODULE_ALIAS("vxfs");
301
302 static int __init
303 vxfs_init(void)
304 {
305         int rv;
306
307         vxfs_inode_cachep = kmem_cache_create("vxfs_inode",
308                         sizeof(struct vxfs_inode_info), 0,
309                         SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
310         if (!vxfs_inode_cachep)
311                 return -ENOMEM;
312         rv = register_filesystem(&vxfs_fs_type);
313         if (rv < 0)
314                 kmem_cache_destroy(vxfs_inode_cachep);
315         return rv;
316 }
317
318 static void __exit
319 vxfs_cleanup(void)
320 {
321         unregister_filesystem(&vxfs_fs_type);
322         /*
323          * Make sure all delayed rcu free inodes are flushed before we
324          * destroy cache.
325          */
326         rcu_barrier();
327         kmem_cache_destroy(vxfs_inode_cachep);
328 }
329
330 module_init(vxfs_init);
331 module_exit(vxfs_cleanup);