blob: dfa775ef4d1da0a40442788889533f87ab4c0bcf [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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>
David Howells726c3342006-06-23 02:02:58 -070043#include <linux/mount.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
45#include "vxfs.h"
46#include "vxfs_extern.h"
47#include "vxfs_dir.h"
48#include "vxfs_inode.h"
49
50
51MODULE_AUTHOR("Christoph Hellwig");
52MODULE_DESCRIPTION("Veritas Filesystem (VxFS) driver");
53MODULE_LICENSE("Dual BSD/GPL");
54
Christoph Hellwig2f137e32016-06-01 08:44:45 +020055static struct kmem_cache *vxfs_inode_cachep;
56
Linus Torvalds1da177e2005-04-16 15:20:36 -070057/**
58 * vxfs_put_super - free superblock resources
59 * @sbp: VFS superblock.
60 *
61 * Description:
62 * vxfs_put_super frees all resources allocated for @sbp
63 * after the last instance of the filesystem is unmounted.
64 */
65
66static void
67vxfs_put_super(struct super_block *sbp)
68{
69 struct vxfs_sb_info *infp = VXFS_SBI(sbp);
70
Krzysztof Błaszkowski0e481d32016-06-01 08:41:11 +020071 iput(infp->vsi_fship);
72 iput(infp->vsi_ilist);
73 iput(infp->vsi_stilist);
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
75 brelse(infp->vsi_bp);
76 kfree(infp);
77}
78
79/**
80 * vxfs_statfs - get filesystem information
David Howells726c3342006-06-23 02:02:58 -070081 * @dentry: VFS dentry to locate superblock
Linus Torvalds1da177e2005-04-16 15:20:36 -070082 * @bufp: output buffer
83 *
84 * Description:
85 * vxfs_statfs fills the statfs buffer @bufp with information
David Howells726c3342006-06-23 02:02:58 -070086 * about the filesystem described by @dentry.
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 *
88 * Returns:
89 * Zero.
90 *
91 * Locking:
92 * No locks held.
93 *
94 * Notes:
95 * This is everything but complete...
96 */
97static int
David Howells726c3342006-06-23 02:02:58 -070098vxfs_statfs(struct dentry *dentry, struct kstatfs *bufp)
Linus Torvalds1da177e2005-04-16 15:20:36 -070099{
David Howells726c3342006-06-23 02:02:58 -0700100 struct vxfs_sb_info *infp = VXFS_SBI(dentry->d_sb);
Krzysztof Błaszkowski0d83f7f2016-05-31 08:45:13 +0200101 struct vxfs_sb *raw_sb = infp->vsi_raw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102
103 bufp->f_type = VXFS_SUPER_MAGIC;
David Howells726c3342006-06-23 02:02:58 -0700104 bufp->f_bsize = dentry->d_sb->s_blocksize;
Krzysztof Błaszkowski0d83f7f2016-05-31 08:45:13 +0200105 bufp->f_blocks = fs32_to_cpu(infp, raw_sb->vs_dsize);
106 bufp->f_bfree = fs32_to_cpu(infp, raw_sb->vs_free);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 bufp->f_bavail = 0;
108 bufp->f_files = 0;
Krzysztof Błaszkowski0d83f7f2016-05-31 08:45:13 +0200109 bufp->f_ffree = fs32_to_cpu(infp, raw_sb->vs_ifree);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 bufp->f_namelen = VXFS_NAMELEN;
111
112 return 0;
113}
114
115static int vxfs_remount(struct super_block *sb, int *flags, char *data)
116{
Theodore Ts'o02b99842014-03-13 10:14:33 -0400117 sync_filesystem(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 *flags |= MS_RDONLY;
119 return 0;
120}
121
Christoph Hellwig2f137e32016-06-01 08:44:45 +0200122static struct inode *vxfs_alloc_inode(struct super_block *sb)
123{
124 struct vxfs_inode_info *vi;
125
126 vi = kmem_cache_alloc(vxfs_inode_cachep, GFP_KERNEL);
127 if (!vi)
128 return NULL;
129 return &vi->vfs_inode;
130}
131
132static void vxfs_i_callback(struct rcu_head *head)
133{
134 struct inode *inode = container_of(head, struct inode, i_rcu);
135
136 kmem_cache_free(vxfs_inode_cachep, VXFS_INO(inode));
137}
138
139static void vxfs_destroy_inode(struct inode *inode)
140{
141 call_rcu(&inode->i_rcu, vxfs_i_callback);
142}
143
Christoph Hellwigf2bf2c72016-06-01 09:18:21 +0200144static const struct super_operations vxfs_super_ops = {
Christoph Hellwig2f137e32016-06-01 08:44:45 +0200145 .alloc_inode = vxfs_alloc_inode,
146 .destroy_inode = vxfs_destroy_inode,
Christoph Hellwigf2bf2c72016-06-01 09:18:21 +0200147 .evict_inode = vxfs_evict_inode,
148 .put_super = vxfs_put_super,
149 .statfs = vxfs_statfs,
150 .remount_fs = vxfs_remount,
151};
Krzysztof Błaszkowski0d83f7f2016-05-31 08:45:13 +0200152
153static int vxfs_try_sb_magic(struct super_block *sbp, int silent,
154 unsigned blk, __fs32 magic)
155{
156 struct buffer_head *bp;
157 struct vxfs_sb *rsbp;
158 struct vxfs_sb_info *infp = VXFS_SBI(sbp);
159 int rc = -ENOMEM;
160
161 bp = sb_bread(sbp, blk);
162 do {
163 if (!bp || !buffer_mapped(bp)) {
164 if (!silent) {
165 printk(KERN_WARNING
166 "vxfs: unable to read disk superblock at %u\n",
167 blk);
168 }
169 break;
170 }
171
172 rc = -EINVAL;
173 rsbp = (struct vxfs_sb *)bp->b_data;
174 if (rsbp->vs_magic != magic) {
175 if (!silent)
176 printk(KERN_NOTICE
177 "vxfs: WRONG superblock magic %08x at %u\n",
178 rsbp->vs_magic, blk);
179 break;
180 }
181
182 rc = 0;
183 infp->vsi_raw = rsbp;
184 infp->vsi_bp = bp;
185 } while (0);
186
187 if (rc) {
188 infp->vsi_raw = NULL;
189 infp->vsi_bp = NULL;
190 brelse(bp);
191 }
192
193 return rc;
194}
195
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196/**
Uwe Kleine-König421f91d2010-06-11 12:17:00 +0200197 * vxfs_read_super - read superblock into memory and initialize filesystem
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 * @sbp: VFS superblock (to fill)
199 * @dp: fs private mount data
200 * @silent: do not complain loudly when sth is wrong
201 *
202 * Description:
203 * We are called on the first mount of a filesystem to read the
204 * superblock into memory and do some basic setup.
205 *
206 * Returns:
207 * The superblock on success, else %NULL.
208 *
209 * Locking:
Jan Blunckdb719222010-08-15 22:51:10 +0200210 * We are under @sbp->s_lock.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 */
212static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
213{
214 struct vxfs_sb_info *infp;
215 struct vxfs_sb *rsbp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 u_long bsize;
217 struct inode *root;
David Howellsd0b07942008-02-07 00:15:39 -0800218 int ret = -EINVAL;
Krzysztof Błaszkowski0d83f7f2016-05-31 08:45:13 +0200219 u32 j;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
221 sbp->s_flags |= MS_RDONLY;
222
Pekka Enberge915fc42005-09-06 15:18:35 -0700223 infp = kzalloc(sizeof(*infp), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 if (!infp) {
225 printk(KERN_WARNING "vxfs: unable to allocate incore superblock\n");
226 return -ENOMEM;
227 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228
229 bsize = sb_min_blocksize(sbp, BLOCK_SIZE);
230 if (!bsize) {
231 printk(KERN_WARNING "vxfs: unable to set blocksize\n");
232 goto out;
233 }
234
Christoph Hellwig2f137e32016-06-01 08:44:45 +0200235 sbp->s_op = &vxfs_super_ops;
Krzysztof Błaszkowski0d83f7f2016-05-31 08:45:13 +0200236 sbp->s_fs_info = infp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
Krzysztof Błaszkowski0d83f7f2016-05-31 08:45:13 +0200238 if (!vxfs_try_sb_magic(sbp, silent, 1,
239 (__force __fs32)cpu_to_le32(VXFS_SUPER_MAGIC))) {
240 /* Unixware, x86 */
241 infp->byte_order = VXFS_BO_LE;
242 } else if (!vxfs_try_sb_magic(sbp, silent, 8,
243 (__force __fs32)cpu_to_be32(VXFS_SUPER_MAGIC))) {
244 /* HP-UX, parisc */
245 infp->byte_order = VXFS_BO_BE;
246 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 if (!silent)
Krzysztof Błaszkowski0d83f7f2016-05-31 08:45:13 +0200248 printk(KERN_NOTICE "vxfs: can't find superblock.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 goto out;
250 }
251
Krzysztof Błaszkowski0d83f7f2016-05-31 08:45:13 +0200252 rsbp = infp->vsi_raw;
253 j = fs32_to_cpu(infp, rsbp->vs_version);
254 if ((j < 2 || j > 4) && !silent) {
255 printk(KERN_NOTICE "vxfs: unsupported VxFS version (%d)\n", j);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 goto out;
257 }
258
259#ifdef DIAGNOSTIC
Krzysztof Błaszkowski0d83f7f2016-05-31 08:45:13 +0200260 printk(KERN_DEBUG "vxfs: supported VxFS version (%d)\n", j);
261 printk(KERN_DEBUG "vxfs: blocksize: %d\n",
262 fs32_to_cpu(infp, rsbp->vs_bsize));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263#endif
264
Krzysztof Błaszkowski0d83f7f2016-05-31 08:45:13 +0200265 sbp->s_magic = fs32_to_cpu(infp, rsbp->vs_magic);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
Krzysztof Błaszkowski0d83f7f2016-05-31 08:45:13 +0200267 infp->vsi_oltext = fs32_to_cpu(infp, rsbp->vs_oltext[0]);
268 infp->vsi_oltsize = fs32_to_cpu(infp, rsbp->vs_oltsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269
Krzysztof Błaszkowski0d83f7f2016-05-31 08:45:13 +0200270 j = fs32_to_cpu(infp, rsbp->vs_bsize);
271 if (!sb_set_blocksize(sbp, j)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 printk(KERN_WARNING "vxfs: unable to set final block size\n");
273 goto out;
274 }
275
276 if (vxfs_read_olt(sbp, bsize)) {
277 printk(KERN_WARNING "vxfs: unable to read olt\n");
278 goto out;
279 }
280
281 if (vxfs_read_fshead(sbp)) {
282 printk(KERN_WARNING "vxfs: unable to read fshead\n");
283 goto out;
284 }
285
David Howellsd0b07942008-02-07 00:15:39 -0800286 root = vxfs_iget(sbp, VXFS_ROOT_INO);
287 if (IS_ERR(root)) {
288 ret = PTR_ERR(root);
289 goto out;
290 }
Al Viro48fde702012-01-08 22:15:13 -0500291 sbp->s_root = d_make_root(root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 if (!sbp->s_root) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 printk(KERN_WARNING "vxfs: unable to get root dentry.\n");
294 goto out_free_ilist;
295 }
296
297 return 0;
298
299out_free_ilist:
Krzysztof Błaszkowski0e481d32016-06-01 08:41:11 +0200300 iput(infp->vsi_fship);
301 iput(infp->vsi_ilist);
302 iput(infp->vsi_stilist);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303out:
Krzysztof Błaszkowski0d83f7f2016-05-31 08:45:13 +0200304 brelse(infp->vsi_bp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 kfree(infp);
David Howellsd0b07942008-02-07 00:15:39 -0800306 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307}
308
309/*
310 * The usual module blurb.
311 */
Al Viro152a0832010-07-25 00:46:55 +0400312static struct dentry *vxfs_mount(struct file_system_type *fs_type,
313 int flags, const char *dev_name, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314{
Al Viro152a0832010-07-25 00:46:55 +0400315 return mount_bdev(fs_type, flags, dev_name, data, vxfs_fill_super);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316}
317
318static struct file_system_type vxfs_fs_type = {
319 .owner = THIS_MODULE,
320 .name = "vxfs",
Al Viro152a0832010-07-25 00:46:55 +0400321 .mount = vxfs_mount,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 .kill_sb = kill_block_super,
323 .fs_flags = FS_REQUIRES_DEV,
324};
Eric W. Biederman7f78e032013-03-02 19:39:14 -0800325MODULE_ALIAS_FS("vxfs"); /* makes mount -t vxfs autoload the module */
Eric W. Biedermanfa7614dd2013-03-12 18:27:41 -0700326MODULE_ALIAS("vxfs");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
328static int __init
329vxfs_init(void)
330{
Alexey Dobriyana4376e12006-09-29 02:01:04 -0700331 int rv;
332
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 vxfs_inode_cachep = kmem_cache_create("vxfs_inode",
Paul Mundt20c2df82007-07-20 10:11:58 +0900334 sizeof(struct vxfs_inode_info), 0,
335 SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
Alexey Dobriyana4376e12006-09-29 02:01:04 -0700336 if (!vxfs_inode_cachep)
337 return -ENOMEM;
338 rv = register_filesystem(&vxfs_fs_type);
339 if (rv < 0)
340 kmem_cache_destroy(vxfs_inode_cachep);
341 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342}
343
344static void __exit
345vxfs_cleanup(void)
346{
347 unregister_filesystem(&vxfs_fs_type);
Kirill A. Shutemov8c0a8532012-09-26 11:33:07 +1000348 /*
349 * Make sure all delayed rcu free inodes are flushed before we
350 * destroy cache.
351 */
352 rcu_barrier();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 kmem_cache_destroy(vxfs_inode_cachep);
354}
355
356module_init(vxfs_init);
357module_exit(vxfs_cleanup);