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 |
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(sbi: infp, a: fshp->olt_fsino[0]); |
23 | } |
24 | |
25 | static inline void |
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(sbi: infp, a: ilistp->olt_iext[0]); |
30 | } |
31 | |
32 | static inline u_long |
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 |
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(sb: sbp, block: vxfs_oblock(sbp, block: 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(sbi: infp, a: 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(sbi: infp, a: 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(sbi: infp, a: ocp->olt_type)) { |
88 | case VXFS_OLT_FSHEAD: |
89 | vxfs_get_fshead(fshp: (struct vxfs_oltfshead *)oaddr, infp); |
90 | break; |
91 | case VXFS_OLT_ILIST: |
92 | vxfs_get_ilist(ilistp: (struct vxfs_oltilist *)oaddr, infp); |
93 | break; |
94 | } |
95 | |
96 | oaddr += fs32_to_cpu(sbi: infp, a: ocp->olt_size); |
97 | } |
98 | |
99 | brelse(bh: bp); |
100 | return (infp->vsi_fshino && infp->vsi_iext) ? 0 : -EINVAL; |
101 | |
102 | fail: |
103 | brelse(bh: bp); |
104 | return -EINVAL; |
105 | } |
106 | |