162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2000-2001 Christoph Hellwig.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci/*
762306a36Sopenharmony_ci * Veritas filesystem driver - object location table support.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci#include <linux/fs.h>
1062306a36Sopenharmony_ci#include <linux/buffer_head.h>
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include "vxfs.h"
1462306a36Sopenharmony_ci#include "vxfs_olt.h"
1562306a36Sopenharmony_ci#include "vxfs_extern.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistatic inline void
1962306a36Sopenharmony_civxfs_get_fshead(struct vxfs_oltfshead *fshp, struct vxfs_sb_info *infp)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	BUG_ON(infp->vsi_fshino);
2262306a36Sopenharmony_ci	infp->vsi_fshino = fs32_to_cpu(infp, fshp->olt_fsino[0]);
2362306a36Sopenharmony_ci}
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic inline void
2662306a36Sopenharmony_civxfs_get_ilist(struct vxfs_oltilist *ilistp, struct vxfs_sb_info *infp)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	BUG_ON(infp->vsi_iext);
2962306a36Sopenharmony_ci	infp->vsi_iext = fs32_to_cpu(infp, ilistp->olt_iext[0]);
3062306a36Sopenharmony_ci}
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic inline u_long
3362306a36Sopenharmony_civxfs_oblock(struct super_block *sbp, daddr_t block, u_long bsize)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	BUG_ON(sbp->s_blocksize % bsize);
3662306a36Sopenharmony_ci	return (block * (sbp->s_blocksize / bsize));
3762306a36Sopenharmony_ci}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/**
4162306a36Sopenharmony_ci * vxfs_read_olt - read olt
4262306a36Sopenharmony_ci * @sbp:	superblock of the filesystem
4362306a36Sopenharmony_ci * @bsize:	blocksize of the filesystem
4462306a36Sopenharmony_ci *
4562306a36Sopenharmony_ci * Description:
4662306a36Sopenharmony_ci *   vxfs_read_olt reads the olt of the filesystem described by @sbp
4762306a36Sopenharmony_ci *   into main memory and does some basic setup.
4862306a36Sopenharmony_ci *
4962306a36Sopenharmony_ci * Returns:
5062306a36Sopenharmony_ci *   Zero on success, else a negative error code.
5162306a36Sopenharmony_ci */
5262306a36Sopenharmony_ciint
5362306a36Sopenharmony_civxfs_read_olt(struct super_block *sbp, u_long bsize)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	struct vxfs_sb_info	*infp = VXFS_SBI(sbp);
5662306a36Sopenharmony_ci	struct buffer_head	*bp;
5762306a36Sopenharmony_ci	struct vxfs_olt		*op;
5862306a36Sopenharmony_ci	char			*oaddr, *eaddr;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	bp = sb_bread(sbp, vxfs_oblock(sbp, infp->vsi_oltext, bsize));
6162306a36Sopenharmony_ci	if (!bp || !bp->b_data)
6262306a36Sopenharmony_ci		goto fail;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	op = (struct vxfs_olt *)bp->b_data;
6562306a36Sopenharmony_ci	if (fs32_to_cpu(infp, op->olt_magic) != VXFS_OLT_MAGIC) {
6662306a36Sopenharmony_ci		printk(KERN_NOTICE "vxfs: ivalid olt magic number\n");
6762306a36Sopenharmony_ci		goto fail;
6862306a36Sopenharmony_ci	}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	/*
7162306a36Sopenharmony_ci	 * It is in theory possible that vsi_oltsize is > 1.
7262306a36Sopenharmony_ci	 * I've not seen any such filesystem yet and I'm lazy..  --hch
7362306a36Sopenharmony_ci	 */
7462306a36Sopenharmony_ci	if (infp->vsi_oltsize > 1) {
7562306a36Sopenharmony_ci		printk(KERN_NOTICE "vxfs: oltsize > 1 detected.\n");
7662306a36Sopenharmony_ci		printk(KERN_NOTICE "vxfs: please notify hch@infradead.org\n");
7762306a36Sopenharmony_ci		goto fail;
7862306a36Sopenharmony_ci	}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	oaddr = bp->b_data + fs32_to_cpu(infp, op->olt_size);
8162306a36Sopenharmony_ci	eaddr = bp->b_data + (infp->vsi_oltsize * sbp->s_blocksize);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	while (oaddr < eaddr) {
8462306a36Sopenharmony_ci		struct vxfs_oltcommon	*ocp =
8562306a36Sopenharmony_ci			(struct vxfs_oltcommon *)oaddr;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci		switch (fs32_to_cpu(infp, ocp->olt_type)) {
8862306a36Sopenharmony_ci		case VXFS_OLT_FSHEAD:
8962306a36Sopenharmony_ci			vxfs_get_fshead((struct vxfs_oltfshead *)oaddr, infp);
9062306a36Sopenharmony_ci			break;
9162306a36Sopenharmony_ci		case VXFS_OLT_ILIST:
9262306a36Sopenharmony_ci			vxfs_get_ilist((struct vxfs_oltilist *)oaddr, infp);
9362306a36Sopenharmony_ci			break;
9462306a36Sopenharmony_ci		}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci		oaddr += fs32_to_cpu(infp, ocp->olt_size);
9762306a36Sopenharmony_ci	}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	brelse(bp);
10062306a36Sopenharmony_ci	return (infp->vsi_fshino && infp->vsi_iext) ? 0 : -EINVAL;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cifail:
10362306a36Sopenharmony_ci	brelse(bp);
10462306a36Sopenharmony_ci	return -EINVAL;
10562306a36Sopenharmony_ci}
106