1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2000-2001 Christoph Hellwig.
4  */
5 
6 /*
7  * Veritas filesystem driver - object location table support.
8  */
9 #include <linux/fs.h>
10 #include <linux/buffer_head.h>
11 #include <linux/kernel.h>
12 
13 #include "vxfs.h"
14 #include "vxfs_olt.h"
15 #include "vxfs_extern.h"
16 
17 
18 static inline void
vxfs_get_fshead(struct vxfs_oltfshead * fshp,struct vxfs_sb_info * infp)19 vxfs_get_fshead(struct vxfs_oltfshead *fshp, struct vxfs_sb_info *infp)
20 {
21 	BUG_ON(infp->vsi_fshino);
22 	infp->vsi_fshino = fs32_to_cpu(infp, fshp->olt_fsino[0]);
23 }
24 
25 static inline void
vxfs_get_ilist(struct vxfs_oltilist * ilistp,struct vxfs_sb_info * infp)26 vxfs_get_ilist(struct vxfs_oltilist *ilistp, struct vxfs_sb_info *infp)
27 {
28 	BUG_ON(infp->vsi_iext);
29 	infp->vsi_iext = fs32_to_cpu(infp, ilistp->olt_iext[0]);
30 }
31 
32 static inline u_long
vxfs_oblock(struct super_block * sbp,daddr_t block,u_long bsize)33 vxfs_oblock(struct super_block *sbp, daddr_t block, u_long bsize)
34 {
35 	BUG_ON(sbp->s_blocksize % bsize);
36 	return (block * (sbp->s_blocksize / bsize));
37 }
38 
39 
40 /**
41  * vxfs_read_olt - read olt
42  * @sbp:	superblock of the filesystem
43  * @bsize:	blocksize of the filesystem
44  *
45  * Description:
46  *   vxfs_read_olt reads the olt of the filesystem described by @sbp
47  *   into main memory and does some basic setup.
48  *
49  * Returns:
50  *   Zero on success, else a negative error code.
51  */
52 int
vxfs_read_olt(struct super_block * sbp,u_long bsize)53 vxfs_read_olt(struct super_block *sbp, u_long bsize)
54 {
55 	struct vxfs_sb_info	*infp = VXFS_SBI(sbp);
56 	struct buffer_head	*bp;
57 	struct vxfs_olt		*op;
58 	char			*oaddr, *eaddr;
59 
60 	bp = sb_bread(sbp, vxfs_oblock(sbp, infp->vsi_oltext, bsize));
61 	if (!bp || !bp->b_data)
62 		goto fail;
63 
64 	op = (struct vxfs_olt *)bp->b_data;
65 	if (fs32_to_cpu(infp, op->olt_magic) != VXFS_OLT_MAGIC) {
66 		printk(KERN_NOTICE "vxfs: ivalid olt magic number\n");
67 		goto fail;
68 	}
69 
70 	/*
71 	 * It is in theory possible that vsi_oltsize is > 1.
72 	 * I've not seen any such filesystem yet and I'm lazy..  --hch
73 	 */
74 	if (infp->vsi_oltsize > 1) {
75 		printk(KERN_NOTICE "vxfs: oltsize > 1 detected.\n");
76 		printk(KERN_NOTICE "vxfs: please notify hch@infradead.org\n");
77 		goto fail;
78 	}
79 
80 	oaddr = bp->b_data + fs32_to_cpu(infp, op->olt_size);
81 	eaddr = bp->b_data + (infp->vsi_oltsize * sbp->s_blocksize);
82 
83 	while (oaddr < eaddr) {
84 		struct vxfs_oltcommon	*ocp =
85 			(struct vxfs_oltcommon *)oaddr;
86 
87 		switch (fs32_to_cpu(infp, ocp->olt_type)) {
88 		case VXFS_OLT_FSHEAD:
89 			vxfs_get_fshead((struct vxfs_oltfshead *)oaddr, infp);
90 			break;
91 		case VXFS_OLT_ILIST:
92 			vxfs_get_ilist((struct vxfs_oltilist *)oaddr, infp);
93 			break;
94 		}
95 
96 		oaddr += fs32_to_cpu(infp, ocp->olt_size);
97 	}
98 
99 	brelse(bp);
100 	return (infp->vsi_fshino && infp->vsi_iext) ? 0 : -EINVAL;
101 
102 fail:
103 	brelse(bp);
104 	return -EINVAL;
105 }
106