162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/ufs/cylinder.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1998 662306a36Sopenharmony_ci * Daniel Pirkl <daniel.pirkl@email.cz> 762306a36Sopenharmony_ci * Charles University, Faculty of Mathematics and Physics 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * ext2 - inode (block) bitmap caching inspired 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/fs.h> 1362306a36Sopenharmony_ci#include <linux/time.h> 1462306a36Sopenharmony_ci#include <linux/stat.h> 1562306a36Sopenharmony_ci#include <linux/string.h> 1662306a36Sopenharmony_ci#include <linux/bitops.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <asm/byteorder.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "ufs_fs.h" 2162306a36Sopenharmony_ci#include "ufs.h" 2262306a36Sopenharmony_ci#include "swab.h" 2362306a36Sopenharmony_ci#include "util.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* 2662306a36Sopenharmony_ci * Read cylinder group into cache. The memory space for ufs_cg_private_info 2762306a36Sopenharmony_ci * structure is already allocated during ufs_read_super. 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_cistatic void ufs_read_cylinder (struct super_block * sb, 3062306a36Sopenharmony_ci unsigned cgno, unsigned bitmap_nr) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci struct ufs_sb_info * sbi = UFS_SB(sb); 3362306a36Sopenharmony_ci struct ufs_sb_private_info * uspi; 3462306a36Sopenharmony_ci struct ufs_cg_private_info * ucpi; 3562306a36Sopenharmony_ci struct ufs_cylinder_group * ucg; 3662306a36Sopenharmony_ci unsigned i, j; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci UFSD("ENTER, cgno %u, bitmap_nr %u\n", cgno, bitmap_nr); 3962306a36Sopenharmony_ci uspi = sbi->s_uspi; 4062306a36Sopenharmony_ci ucpi = sbi->s_ucpi[bitmap_nr]; 4162306a36Sopenharmony_ci ucg = (struct ufs_cylinder_group *)sbi->s_ucg[cgno]->b_data; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci UCPI_UBH(ucpi)->fragment = ufs_cgcmin(cgno); 4462306a36Sopenharmony_ci UCPI_UBH(ucpi)->count = uspi->s_cgsize >> sb->s_blocksize_bits; 4562306a36Sopenharmony_ci /* 4662306a36Sopenharmony_ci * We have already the first fragment of cylinder group block in buffer 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_ci UCPI_UBH(ucpi)->bh[0] = sbi->s_ucg[cgno]; 4962306a36Sopenharmony_ci for (i = 1; i < UCPI_UBH(ucpi)->count; i++) 5062306a36Sopenharmony_ci if (!(UCPI_UBH(ucpi)->bh[i] = sb_bread(sb, UCPI_UBH(ucpi)->fragment + i))) 5162306a36Sopenharmony_ci goto failed; 5262306a36Sopenharmony_ci sbi->s_cgno[bitmap_nr] = cgno; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci ucpi->c_cgx = fs32_to_cpu(sb, ucg->cg_cgx); 5562306a36Sopenharmony_ci ucpi->c_ncyl = fs16_to_cpu(sb, ucg->cg_ncyl); 5662306a36Sopenharmony_ci ucpi->c_niblk = fs16_to_cpu(sb, ucg->cg_niblk); 5762306a36Sopenharmony_ci ucpi->c_ndblk = fs32_to_cpu(sb, ucg->cg_ndblk); 5862306a36Sopenharmony_ci ucpi->c_rotor = fs32_to_cpu(sb, ucg->cg_rotor); 5962306a36Sopenharmony_ci ucpi->c_frotor = fs32_to_cpu(sb, ucg->cg_frotor); 6062306a36Sopenharmony_ci ucpi->c_irotor = fs32_to_cpu(sb, ucg->cg_irotor); 6162306a36Sopenharmony_ci ucpi->c_btotoff = fs32_to_cpu(sb, ucg->cg_btotoff); 6262306a36Sopenharmony_ci ucpi->c_boff = fs32_to_cpu(sb, ucg->cg_boff); 6362306a36Sopenharmony_ci ucpi->c_iusedoff = fs32_to_cpu(sb, ucg->cg_iusedoff); 6462306a36Sopenharmony_ci ucpi->c_freeoff = fs32_to_cpu(sb, ucg->cg_freeoff); 6562306a36Sopenharmony_ci ucpi->c_nextfreeoff = fs32_to_cpu(sb, ucg->cg_nextfreeoff); 6662306a36Sopenharmony_ci ucpi->c_clustersumoff = fs32_to_cpu(sb, ucg->cg_u.cg_44.cg_clustersumoff); 6762306a36Sopenharmony_ci ucpi->c_clusteroff = fs32_to_cpu(sb, ucg->cg_u.cg_44.cg_clusteroff); 6862306a36Sopenharmony_ci ucpi->c_nclusterblks = fs32_to_cpu(sb, ucg->cg_u.cg_44.cg_nclusterblks); 6962306a36Sopenharmony_ci UFSD("EXIT\n"); 7062306a36Sopenharmony_ci return; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cifailed: 7362306a36Sopenharmony_ci for (j = 1; j < i; j++) 7462306a36Sopenharmony_ci brelse (sbi->s_ucg[j]); 7562306a36Sopenharmony_ci sbi->s_cgno[bitmap_nr] = UFS_CGNO_EMPTY; 7662306a36Sopenharmony_ci ufs_error (sb, "ufs_read_cylinder", "can't read cylinder group block %u", cgno); 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/* 8062306a36Sopenharmony_ci * Remove cylinder group from cache, doesn't release memory 8162306a36Sopenharmony_ci * allocated for cylinder group (this is done at ufs_put_super only). 8262306a36Sopenharmony_ci */ 8362306a36Sopenharmony_civoid ufs_put_cylinder (struct super_block * sb, unsigned bitmap_nr) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci struct ufs_sb_info * sbi = UFS_SB(sb); 8662306a36Sopenharmony_ci struct ufs_sb_private_info * uspi; 8762306a36Sopenharmony_ci struct ufs_cg_private_info * ucpi; 8862306a36Sopenharmony_ci struct ufs_cylinder_group * ucg; 8962306a36Sopenharmony_ci unsigned i; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci UFSD("ENTER, bitmap_nr %u\n", bitmap_nr); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci uspi = sbi->s_uspi; 9462306a36Sopenharmony_ci if (sbi->s_cgno[bitmap_nr] == UFS_CGNO_EMPTY) { 9562306a36Sopenharmony_ci UFSD("EXIT\n"); 9662306a36Sopenharmony_ci return; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci ucpi = sbi->s_ucpi[bitmap_nr]; 9962306a36Sopenharmony_ci ucg = ubh_get_ucg(UCPI_UBH(ucpi)); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci if (uspi->s_ncg > UFS_MAX_GROUP_LOADED && bitmap_nr >= sbi->s_cg_loaded) { 10262306a36Sopenharmony_ci ufs_panic (sb, "ufs_put_cylinder", "internal error"); 10362306a36Sopenharmony_ci return; 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci /* 10662306a36Sopenharmony_ci * rotor is not so important data, so we put it to disk 10762306a36Sopenharmony_ci * at the end of working with cylinder 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_ci ucg->cg_rotor = cpu_to_fs32(sb, ucpi->c_rotor); 11062306a36Sopenharmony_ci ucg->cg_frotor = cpu_to_fs32(sb, ucpi->c_frotor); 11162306a36Sopenharmony_ci ucg->cg_irotor = cpu_to_fs32(sb, ucpi->c_irotor); 11262306a36Sopenharmony_ci ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); 11362306a36Sopenharmony_ci for (i = 1; i < UCPI_UBH(ucpi)->count; i++) { 11462306a36Sopenharmony_ci brelse (UCPI_UBH(ucpi)->bh[i]); 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci sbi->s_cgno[bitmap_nr] = UFS_CGNO_EMPTY; 11862306a36Sopenharmony_ci UFSD("EXIT\n"); 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/* 12262306a36Sopenharmony_ci * Find cylinder group in cache and return it as pointer. 12362306a36Sopenharmony_ci * If cylinder group is not in cache, we will load it from disk. 12462306a36Sopenharmony_ci * 12562306a36Sopenharmony_ci * The cache is managed by LRU algorithm. 12662306a36Sopenharmony_ci */ 12762306a36Sopenharmony_cistruct ufs_cg_private_info * ufs_load_cylinder ( 12862306a36Sopenharmony_ci struct super_block * sb, unsigned cgno) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci struct ufs_sb_info * sbi = UFS_SB(sb); 13162306a36Sopenharmony_ci struct ufs_sb_private_info * uspi; 13262306a36Sopenharmony_ci struct ufs_cg_private_info * ucpi; 13362306a36Sopenharmony_ci unsigned cg, i, j; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci UFSD("ENTER, cgno %u\n", cgno); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci uspi = sbi->s_uspi; 13862306a36Sopenharmony_ci if (cgno >= uspi->s_ncg) { 13962306a36Sopenharmony_ci ufs_panic (sb, "ufs_load_cylinder", "internal error, high number of cg"); 14062306a36Sopenharmony_ci return NULL; 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci /* 14362306a36Sopenharmony_ci * Cylinder group number cg it in cache and it was last used 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_ci if (sbi->s_cgno[0] == cgno) { 14662306a36Sopenharmony_ci UFSD("EXIT\n"); 14762306a36Sopenharmony_ci return sbi->s_ucpi[0]; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci /* 15062306a36Sopenharmony_ci * Number of cylinder groups is not higher than UFS_MAX_GROUP_LOADED 15162306a36Sopenharmony_ci */ 15262306a36Sopenharmony_ci if (uspi->s_ncg <= UFS_MAX_GROUP_LOADED) { 15362306a36Sopenharmony_ci if (sbi->s_cgno[cgno] != UFS_CGNO_EMPTY) { 15462306a36Sopenharmony_ci if (sbi->s_cgno[cgno] != cgno) { 15562306a36Sopenharmony_ci ufs_panic (sb, "ufs_load_cylinder", "internal error, wrong number of cg in cache"); 15662306a36Sopenharmony_ci UFSD("EXIT (FAILED)\n"); 15762306a36Sopenharmony_ci return NULL; 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci else { 16062306a36Sopenharmony_ci UFSD("EXIT\n"); 16162306a36Sopenharmony_ci return sbi->s_ucpi[cgno]; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci } else { 16462306a36Sopenharmony_ci ufs_read_cylinder (sb, cgno, cgno); 16562306a36Sopenharmony_ci UFSD("EXIT\n"); 16662306a36Sopenharmony_ci return sbi->s_ucpi[cgno]; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci /* 17062306a36Sopenharmony_ci * Cylinder group number cg is in cache but it was not last used, 17162306a36Sopenharmony_ci * we will move to the first position 17262306a36Sopenharmony_ci */ 17362306a36Sopenharmony_ci for (i = 0; i < sbi->s_cg_loaded && sbi->s_cgno[i] != cgno; i++); 17462306a36Sopenharmony_ci if (i < sbi->s_cg_loaded && sbi->s_cgno[i] == cgno) { 17562306a36Sopenharmony_ci cg = sbi->s_cgno[i]; 17662306a36Sopenharmony_ci ucpi = sbi->s_ucpi[i]; 17762306a36Sopenharmony_ci for (j = i; j > 0; j--) { 17862306a36Sopenharmony_ci sbi->s_cgno[j] = sbi->s_cgno[j-1]; 17962306a36Sopenharmony_ci sbi->s_ucpi[j] = sbi->s_ucpi[j-1]; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci sbi->s_cgno[0] = cg; 18262306a36Sopenharmony_ci sbi->s_ucpi[0] = ucpi; 18362306a36Sopenharmony_ci /* 18462306a36Sopenharmony_ci * Cylinder group number cg is not in cache, we will read it from disk 18562306a36Sopenharmony_ci * and put it to the first position 18662306a36Sopenharmony_ci */ 18762306a36Sopenharmony_ci } else { 18862306a36Sopenharmony_ci if (sbi->s_cg_loaded < UFS_MAX_GROUP_LOADED) 18962306a36Sopenharmony_ci sbi->s_cg_loaded++; 19062306a36Sopenharmony_ci else 19162306a36Sopenharmony_ci ufs_put_cylinder (sb, UFS_MAX_GROUP_LOADED-1); 19262306a36Sopenharmony_ci ucpi = sbi->s_ucpi[sbi->s_cg_loaded - 1]; 19362306a36Sopenharmony_ci for (j = sbi->s_cg_loaded - 1; j > 0; j--) { 19462306a36Sopenharmony_ci sbi->s_cgno[j] = sbi->s_cgno[j-1]; 19562306a36Sopenharmony_ci sbi->s_ucpi[j] = sbi->s_ucpi[j-1]; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci sbi->s_ucpi[0] = ucpi; 19862306a36Sopenharmony_ci ufs_read_cylinder (sb, cgno, 0); 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci UFSD("EXIT\n"); 20162306a36Sopenharmony_ci return sbi->s_ucpi[0]; 20262306a36Sopenharmony_ci} 203