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(infp, 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(infp, 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(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