18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/fs/ufs/cylinder.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1998 68c2ecf20Sopenharmony_ci * Daniel Pirkl <daniel.pirkl@email.cz> 78c2ecf20Sopenharmony_ci * Charles University, Faculty of Mathematics and Physics 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * ext2 - inode (block) bitmap caching inspired 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/fs.h> 138c2ecf20Sopenharmony_ci#include <linux/time.h> 148c2ecf20Sopenharmony_ci#include <linux/stat.h> 158c2ecf20Sopenharmony_ci#include <linux/string.h> 168c2ecf20Sopenharmony_ci#include <linux/bitops.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "ufs_fs.h" 218c2ecf20Sopenharmony_ci#include "ufs.h" 228c2ecf20Sopenharmony_ci#include "swab.h" 238c2ecf20Sopenharmony_ci#include "util.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* 268c2ecf20Sopenharmony_ci * Read cylinder group into cache. The memory space for ufs_cg_private_info 278c2ecf20Sopenharmony_ci * structure is already allocated during ufs_read_super. 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_cistatic void ufs_read_cylinder (struct super_block * sb, 308c2ecf20Sopenharmony_ci unsigned cgno, unsigned bitmap_nr) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci struct ufs_sb_info * sbi = UFS_SB(sb); 338c2ecf20Sopenharmony_ci struct ufs_sb_private_info * uspi; 348c2ecf20Sopenharmony_ci struct ufs_cg_private_info * ucpi; 358c2ecf20Sopenharmony_ci struct ufs_cylinder_group * ucg; 368c2ecf20Sopenharmony_ci unsigned i, j; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci UFSD("ENTER, cgno %u, bitmap_nr %u\n", cgno, bitmap_nr); 398c2ecf20Sopenharmony_ci uspi = sbi->s_uspi; 408c2ecf20Sopenharmony_ci ucpi = sbi->s_ucpi[bitmap_nr]; 418c2ecf20Sopenharmony_ci ucg = (struct ufs_cylinder_group *)sbi->s_ucg[cgno]->b_data; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci UCPI_UBH(ucpi)->fragment = ufs_cgcmin(cgno); 448c2ecf20Sopenharmony_ci UCPI_UBH(ucpi)->count = uspi->s_cgsize >> sb->s_blocksize_bits; 458c2ecf20Sopenharmony_ci /* 468c2ecf20Sopenharmony_ci * We have already the first fragment of cylinder group block in buffer 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_ci UCPI_UBH(ucpi)->bh[0] = sbi->s_ucg[cgno]; 498c2ecf20Sopenharmony_ci for (i = 1; i < UCPI_UBH(ucpi)->count; i++) 508c2ecf20Sopenharmony_ci if (!(UCPI_UBH(ucpi)->bh[i] = sb_bread(sb, UCPI_UBH(ucpi)->fragment + i))) 518c2ecf20Sopenharmony_ci goto failed; 528c2ecf20Sopenharmony_ci sbi->s_cgno[bitmap_nr] = cgno; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci ucpi->c_cgx = fs32_to_cpu(sb, ucg->cg_cgx); 558c2ecf20Sopenharmony_ci ucpi->c_ncyl = fs16_to_cpu(sb, ucg->cg_ncyl); 568c2ecf20Sopenharmony_ci ucpi->c_niblk = fs16_to_cpu(sb, ucg->cg_niblk); 578c2ecf20Sopenharmony_ci ucpi->c_ndblk = fs32_to_cpu(sb, ucg->cg_ndblk); 588c2ecf20Sopenharmony_ci ucpi->c_rotor = fs32_to_cpu(sb, ucg->cg_rotor); 598c2ecf20Sopenharmony_ci ucpi->c_frotor = fs32_to_cpu(sb, ucg->cg_frotor); 608c2ecf20Sopenharmony_ci ucpi->c_irotor = fs32_to_cpu(sb, ucg->cg_irotor); 618c2ecf20Sopenharmony_ci ucpi->c_btotoff = fs32_to_cpu(sb, ucg->cg_btotoff); 628c2ecf20Sopenharmony_ci ucpi->c_boff = fs32_to_cpu(sb, ucg->cg_boff); 638c2ecf20Sopenharmony_ci ucpi->c_iusedoff = fs32_to_cpu(sb, ucg->cg_iusedoff); 648c2ecf20Sopenharmony_ci ucpi->c_freeoff = fs32_to_cpu(sb, ucg->cg_freeoff); 658c2ecf20Sopenharmony_ci ucpi->c_nextfreeoff = fs32_to_cpu(sb, ucg->cg_nextfreeoff); 668c2ecf20Sopenharmony_ci ucpi->c_clustersumoff = fs32_to_cpu(sb, ucg->cg_u.cg_44.cg_clustersumoff); 678c2ecf20Sopenharmony_ci ucpi->c_clusteroff = fs32_to_cpu(sb, ucg->cg_u.cg_44.cg_clusteroff); 688c2ecf20Sopenharmony_ci ucpi->c_nclusterblks = fs32_to_cpu(sb, ucg->cg_u.cg_44.cg_nclusterblks); 698c2ecf20Sopenharmony_ci UFSD("EXIT\n"); 708c2ecf20Sopenharmony_ci return; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cifailed: 738c2ecf20Sopenharmony_ci for (j = 1; j < i; j++) 748c2ecf20Sopenharmony_ci brelse (sbi->s_ucg[j]); 758c2ecf20Sopenharmony_ci sbi->s_cgno[bitmap_nr] = UFS_CGNO_EMPTY; 768c2ecf20Sopenharmony_ci ufs_error (sb, "ufs_read_cylinder", "can't read cylinder group block %u", cgno); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/* 808c2ecf20Sopenharmony_ci * Remove cylinder group from cache, doesn't release memory 818c2ecf20Sopenharmony_ci * allocated for cylinder group (this is done at ufs_put_super only). 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_civoid ufs_put_cylinder (struct super_block * sb, unsigned bitmap_nr) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci struct ufs_sb_info * sbi = UFS_SB(sb); 868c2ecf20Sopenharmony_ci struct ufs_sb_private_info * uspi; 878c2ecf20Sopenharmony_ci struct ufs_cg_private_info * ucpi; 888c2ecf20Sopenharmony_ci struct ufs_cylinder_group * ucg; 898c2ecf20Sopenharmony_ci unsigned i; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci UFSD("ENTER, bitmap_nr %u\n", bitmap_nr); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci uspi = sbi->s_uspi; 948c2ecf20Sopenharmony_ci if (sbi->s_cgno[bitmap_nr] == UFS_CGNO_EMPTY) { 958c2ecf20Sopenharmony_ci UFSD("EXIT\n"); 968c2ecf20Sopenharmony_ci return; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci ucpi = sbi->s_ucpi[bitmap_nr]; 998c2ecf20Sopenharmony_ci ucg = ubh_get_ucg(UCPI_UBH(ucpi)); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (uspi->s_ncg > UFS_MAX_GROUP_LOADED && bitmap_nr >= sbi->s_cg_loaded) { 1028c2ecf20Sopenharmony_ci ufs_panic (sb, "ufs_put_cylinder", "internal error"); 1038c2ecf20Sopenharmony_ci return; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci /* 1068c2ecf20Sopenharmony_ci * rotor is not so important data, so we put it to disk 1078c2ecf20Sopenharmony_ci * at the end of working with cylinder 1088c2ecf20Sopenharmony_ci */ 1098c2ecf20Sopenharmony_ci ucg->cg_rotor = cpu_to_fs32(sb, ucpi->c_rotor); 1108c2ecf20Sopenharmony_ci ucg->cg_frotor = cpu_to_fs32(sb, ucpi->c_frotor); 1118c2ecf20Sopenharmony_ci ucg->cg_irotor = cpu_to_fs32(sb, ucpi->c_irotor); 1128c2ecf20Sopenharmony_ci ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); 1138c2ecf20Sopenharmony_ci for (i = 1; i < UCPI_UBH(ucpi)->count; i++) { 1148c2ecf20Sopenharmony_ci brelse (UCPI_UBH(ucpi)->bh[i]); 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci sbi->s_cgno[bitmap_nr] = UFS_CGNO_EMPTY; 1188c2ecf20Sopenharmony_ci UFSD("EXIT\n"); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci/* 1228c2ecf20Sopenharmony_ci * Find cylinder group in cache and return it as pointer. 1238c2ecf20Sopenharmony_ci * If cylinder group is not in cache, we will load it from disk. 1248c2ecf20Sopenharmony_ci * 1258c2ecf20Sopenharmony_ci * The cache is managed by LRU algorithm. 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_cistruct ufs_cg_private_info * ufs_load_cylinder ( 1288c2ecf20Sopenharmony_ci struct super_block * sb, unsigned cgno) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci struct ufs_sb_info * sbi = UFS_SB(sb); 1318c2ecf20Sopenharmony_ci struct ufs_sb_private_info * uspi; 1328c2ecf20Sopenharmony_ci struct ufs_cg_private_info * ucpi; 1338c2ecf20Sopenharmony_ci unsigned cg, i, j; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci UFSD("ENTER, cgno %u\n", cgno); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci uspi = sbi->s_uspi; 1388c2ecf20Sopenharmony_ci if (cgno >= uspi->s_ncg) { 1398c2ecf20Sopenharmony_ci ufs_panic (sb, "ufs_load_cylinder", "internal error, high number of cg"); 1408c2ecf20Sopenharmony_ci return NULL; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci /* 1438c2ecf20Sopenharmony_ci * Cylinder group number cg it in cache and it was last used 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_ci if (sbi->s_cgno[0] == cgno) { 1468c2ecf20Sopenharmony_ci UFSD("EXIT\n"); 1478c2ecf20Sopenharmony_ci return sbi->s_ucpi[0]; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci /* 1508c2ecf20Sopenharmony_ci * Number of cylinder groups is not higher than UFS_MAX_GROUP_LOADED 1518c2ecf20Sopenharmony_ci */ 1528c2ecf20Sopenharmony_ci if (uspi->s_ncg <= UFS_MAX_GROUP_LOADED) { 1538c2ecf20Sopenharmony_ci if (sbi->s_cgno[cgno] != UFS_CGNO_EMPTY) { 1548c2ecf20Sopenharmony_ci if (sbi->s_cgno[cgno] != cgno) { 1558c2ecf20Sopenharmony_ci ufs_panic (sb, "ufs_load_cylinder", "internal error, wrong number of cg in cache"); 1568c2ecf20Sopenharmony_ci UFSD("EXIT (FAILED)\n"); 1578c2ecf20Sopenharmony_ci return NULL; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci else { 1608c2ecf20Sopenharmony_ci UFSD("EXIT\n"); 1618c2ecf20Sopenharmony_ci return sbi->s_ucpi[cgno]; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci } else { 1648c2ecf20Sopenharmony_ci ufs_read_cylinder (sb, cgno, cgno); 1658c2ecf20Sopenharmony_ci UFSD("EXIT\n"); 1668c2ecf20Sopenharmony_ci return sbi->s_ucpi[cgno]; 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci /* 1708c2ecf20Sopenharmony_ci * Cylinder group number cg is in cache but it was not last used, 1718c2ecf20Sopenharmony_ci * we will move to the first position 1728c2ecf20Sopenharmony_ci */ 1738c2ecf20Sopenharmony_ci for (i = 0; i < sbi->s_cg_loaded && sbi->s_cgno[i] != cgno; i++); 1748c2ecf20Sopenharmony_ci if (i < sbi->s_cg_loaded && sbi->s_cgno[i] == cgno) { 1758c2ecf20Sopenharmony_ci cg = sbi->s_cgno[i]; 1768c2ecf20Sopenharmony_ci ucpi = sbi->s_ucpi[i]; 1778c2ecf20Sopenharmony_ci for (j = i; j > 0; j--) { 1788c2ecf20Sopenharmony_ci sbi->s_cgno[j] = sbi->s_cgno[j-1]; 1798c2ecf20Sopenharmony_ci sbi->s_ucpi[j] = sbi->s_ucpi[j-1]; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci sbi->s_cgno[0] = cg; 1828c2ecf20Sopenharmony_ci sbi->s_ucpi[0] = ucpi; 1838c2ecf20Sopenharmony_ci /* 1848c2ecf20Sopenharmony_ci * Cylinder group number cg is not in cache, we will read it from disk 1858c2ecf20Sopenharmony_ci * and put it to the first position 1868c2ecf20Sopenharmony_ci */ 1878c2ecf20Sopenharmony_ci } else { 1888c2ecf20Sopenharmony_ci if (sbi->s_cg_loaded < UFS_MAX_GROUP_LOADED) 1898c2ecf20Sopenharmony_ci sbi->s_cg_loaded++; 1908c2ecf20Sopenharmony_ci else 1918c2ecf20Sopenharmony_ci ufs_put_cylinder (sb, UFS_MAX_GROUP_LOADED-1); 1928c2ecf20Sopenharmony_ci ucpi = sbi->s_ucpi[sbi->s_cg_loaded - 1]; 1938c2ecf20Sopenharmony_ci for (j = sbi->s_cg_loaded - 1; j > 0; j--) { 1948c2ecf20Sopenharmony_ci sbi->s_cgno[j] = sbi->s_cgno[j-1]; 1958c2ecf20Sopenharmony_ci sbi->s_ucpi[j] = sbi->s_ucpi[j-1]; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci sbi->s_ucpi[0] = ucpi; 1988c2ecf20Sopenharmony_ci ufs_read_cylinder (sb, cgno, 0); 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci UFSD("EXIT\n"); 2018c2ecf20Sopenharmony_ci return sbi->s_ucpi[0]; 2028c2ecf20Sopenharmony_ci} 203