162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2000-2001 Christoph Hellwig.
462306a36Sopenharmony_ci * Copyright (c) 2016 Krzysztof Blaszkowski
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci/*
862306a36Sopenharmony_ci * Veritas filesystem driver - fileset header routines.
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci#include <linux/fs.h>
1162306a36Sopenharmony_ci#include <linux/buffer_head.h>
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/slab.h>
1462306a36Sopenharmony_ci#include <linux/string.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "vxfs.h"
1762306a36Sopenharmony_ci#include "vxfs_inode.h"
1862306a36Sopenharmony_ci#include "vxfs_extern.h"
1962306a36Sopenharmony_ci#include "vxfs_fshead.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#ifdef DIAGNOSTIC
2362306a36Sopenharmony_cistatic void
2462306a36Sopenharmony_civxfs_dumpfsh(struct vxfs_fsh *fhp)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	printk("\n\ndumping fileset header:\n");
2762306a36Sopenharmony_ci	printk("----------------------------\n");
2862306a36Sopenharmony_ci	printk("version: %u\n", fhp->fsh_version);
2962306a36Sopenharmony_ci	printk("fsindex: %u\n", fhp->fsh_fsindex);
3062306a36Sopenharmony_ci	printk("iauino: %u\tninodes:%u\n",
3162306a36Sopenharmony_ci			fhp->fsh_iauino, fhp->fsh_ninodes);
3262306a36Sopenharmony_ci	printk("maxinode: %u\tlctino: %u\n",
3362306a36Sopenharmony_ci			fhp->fsh_maxinode, fhp->fsh_lctino);
3462306a36Sopenharmony_ci	printk("nau: %u\n", fhp->fsh_nau);
3562306a36Sopenharmony_ci	printk("ilistino[0]: %u\tilistino[1]: %u\n",
3662306a36Sopenharmony_ci			fhp->fsh_ilistino[0], fhp->fsh_ilistino[1]);
3762306a36Sopenharmony_ci}
3862306a36Sopenharmony_ci#endif
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/**
4162306a36Sopenharmony_ci * vxfs_getfsh - read fileset header into memory
4262306a36Sopenharmony_ci * @ip:		the (fake) fileset header inode
4362306a36Sopenharmony_ci * @which:	0 for the structural, 1 for the primary fsh.
4462306a36Sopenharmony_ci *
4562306a36Sopenharmony_ci * Description:
4662306a36Sopenharmony_ci *   vxfs_getfsh reads either the structural or primary fileset header
4762306a36Sopenharmony_ci *   described by @ip into memory.
4862306a36Sopenharmony_ci *
4962306a36Sopenharmony_ci * Returns:
5062306a36Sopenharmony_ci *   The fileset header structure on success, else Zero.
5162306a36Sopenharmony_ci */
5262306a36Sopenharmony_cistatic struct vxfs_fsh *
5362306a36Sopenharmony_civxfs_getfsh(struct inode *ip, int which)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	struct buffer_head		*bp;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	bp = vxfs_bread(ip, which);
5862306a36Sopenharmony_ci	if (bp) {
5962306a36Sopenharmony_ci		struct vxfs_fsh		*fhp;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci		if (!(fhp = kmalloc(sizeof(*fhp), GFP_KERNEL)))
6262306a36Sopenharmony_ci			goto out;
6362306a36Sopenharmony_ci		memcpy(fhp, bp->b_data, sizeof(*fhp));
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci		put_bh(bp);
6662306a36Sopenharmony_ci		return (fhp);
6762306a36Sopenharmony_ci	}
6862306a36Sopenharmony_ciout:
6962306a36Sopenharmony_ci	brelse(bp);
7062306a36Sopenharmony_ci	return NULL;
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci/**
7462306a36Sopenharmony_ci * vxfs_read_fshead - read the fileset headers
7562306a36Sopenharmony_ci * @sbp:	superblock to which the fileset belongs
7662306a36Sopenharmony_ci *
7762306a36Sopenharmony_ci * Description:
7862306a36Sopenharmony_ci *   vxfs_read_fshead will fill the inode and structural inode list in @sb.
7962306a36Sopenharmony_ci *
8062306a36Sopenharmony_ci * Returns:
8162306a36Sopenharmony_ci *   Zero on success, else a negative error code (-EINVAL).
8262306a36Sopenharmony_ci */
8362306a36Sopenharmony_ciint
8462306a36Sopenharmony_civxfs_read_fshead(struct super_block *sbp)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	struct vxfs_sb_info		*infp = VXFS_SBI(sbp);
8762306a36Sopenharmony_ci	struct vxfs_fsh			*pfp, *sfp;
8862306a36Sopenharmony_ci	struct vxfs_inode_info		*vip;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	infp->vsi_fship = vxfs_blkiget(sbp, infp->vsi_iext, infp->vsi_fshino);
9162306a36Sopenharmony_ci	if (!infp->vsi_fship) {
9262306a36Sopenharmony_ci		printk(KERN_ERR "vxfs: unable to read fsh inode\n");
9362306a36Sopenharmony_ci		return -EINVAL;
9462306a36Sopenharmony_ci	}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	vip = VXFS_INO(infp->vsi_fship);
9762306a36Sopenharmony_ci	if (!VXFS_ISFSH(vip)) {
9862306a36Sopenharmony_ci		printk(KERN_ERR "vxfs: fsh list inode is of wrong type (%x)\n",
9962306a36Sopenharmony_ci				vip->vii_mode & VXFS_TYPE_MASK);
10062306a36Sopenharmony_ci		goto out_iput_fship;
10162306a36Sopenharmony_ci	}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci#ifdef DIAGNOSTIC
10462306a36Sopenharmony_ci	printk("vxfs: fsh inode dump:\n");
10562306a36Sopenharmony_ci	vxfs_dumpi(vip, infp->vsi_fshino);
10662306a36Sopenharmony_ci#endif
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	sfp = vxfs_getfsh(infp->vsi_fship, 0);
10962306a36Sopenharmony_ci	if (!sfp) {
11062306a36Sopenharmony_ci		printk(KERN_ERR "vxfs: unable to get structural fsh\n");
11162306a36Sopenharmony_ci		goto out_iput_fship;
11262306a36Sopenharmony_ci	}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci#ifdef DIAGNOSTIC
11562306a36Sopenharmony_ci	vxfs_dumpfsh(sfp);
11662306a36Sopenharmony_ci#endif
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	pfp = vxfs_getfsh(infp->vsi_fship, 1);
11962306a36Sopenharmony_ci	if (!pfp) {
12062306a36Sopenharmony_ci		printk(KERN_ERR "vxfs: unable to get primary fsh\n");
12162306a36Sopenharmony_ci		goto out_free_sfp;
12262306a36Sopenharmony_ci	}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci#ifdef DIAGNOSTIC
12562306a36Sopenharmony_ci	vxfs_dumpfsh(pfp);
12662306a36Sopenharmony_ci#endif
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	infp->vsi_stilist = vxfs_blkiget(sbp, infp->vsi_iext,
12962306a36Sopenharmony_ci			fs32_to_cpu(infp, sfp->fsh_ilistino[0]));
13062306a36Sopenharmony_ci	if (!infp->vsi_stilist) {
13162306a36Sopenharmony_ci		printk(KERN_ERR "vxfs: unable to get structural list inode\n");
13262306a36Sopenharmony_ci		goto out_free_pfp;
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci	if (!VXFS_ISILT(VXFS_INO(infp->vsi_stilist))) {
13562306a36Sopenharmony_ci		printk(KERN_ERR "vxfs: structural list inode is of wrong type (%x)\n",
13662306a36Sopenharmony_ci				VXFS_INO(infp->vsi_stilist)->vii_mode & VXFS_TYPE_MASK);
13762306a36Sopenharmony_ci		goto out_iput_stilist;
13862306a36Sopenharmony_ci	}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	infp->vsi_ilist = vxfs_stiget(sbp, fs32_to_cpu(infp, pfp->fsh_ilistino[0]));
14162306a36Sopenharmony_ci	if (!infp->vsi_ilist) {
14262306a36Sopenharmony_ci		printk(KERN_ERR "vxfs: unable to get inode list inode\n");
14362306a36Sopenharmony_ci		goto out_iput_stilist;
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci	if (!VXFS_ISILT(VXFS_INO(infp->vsi_ilist))) {
14662306a36Sopenharmony_ci		printk(KERN_ERR "vxfs: inode list inode is of wrong type (%x)\n",
14762306a36Sopenharmony_ci				VXFS_INO(infp->vsi_ilist)->vii_mode & VXFS_TYPE_MASK);
14862306a36Sopenharmony_ci		goto out_iput_ilist;
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	kfree(pfp);
15262306a36Sopenharmony_ci	kfree(sfp);
15362306a36Sopenharmony_ci	return 0;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci out_iput_ilist:
15662306a36Sopenharmony_ci 	iput(infp->vsi_ilist);
15762306a36Sopenharmony_ci out_iput_stilist:
15862306a36Sopenharmony_ci 	iput(infp->vsi_stilist);
15962306a36Sopenharmony_ci out_free_pfp:
16062306a36Sopenharmony_ci	kfree(pfp);
16162306a36Sopenharmony_ci out_free_sfp:
16262306a36Sopenharmony_ci 	kfree(sfp);
16362306a36Sopenharmony_ci out_iput_fship:
16462306a36Sopenharmony_ci	iput(infp->vsi_fship);
16562306a36Sopenharmony_ci	return -EINVAL;
16662306a36Sopenharmony_ci}
167