18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/fs/sysv/ialloc.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * minix/bitmap.c 68c2ecf20Sopenharmony_ci * Copyright (C) 1991, 1992 Linus Torvalds 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * ext/freelists.c 98c2ecf20Sopenharmony_ci * Copyright (C) 1992 Remy Card (card@masi.ibp.fr) 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * xenix/alloc.c 128c2ecf20Sopenharmony_ci * Copyright (C) 1992 Doug Evans 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * coh/alloc.c 158c2ecf20Sopenharmony_ci * Copyright (C) 1993 Pascal Haible, Bruno Haible 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * sysv/ialloc.c 188c2ecf20Sopenharmony_ci * Copyright (C) 1993 Bruno Haible 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * This file contains code for allocating/freeing inodes. 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <linux/kernel.h> 248c2ecf20Sopenharmony_ci#include <linux/stddef.h> 258c2ecf20Sopenharmony_ci#include <linux/sched.h> 268c2ecf20Sopenharmony_ci#include <linux/stat.h> 278c2ecf20Sopenharmony_ci#include <linux/string.h> 288c2ecf20Sopenharmony_ci#include <linux/buffer_head.h> 298c2ecf20Sopenharmony_ci#include <linux/writeback.h> 308c2ecf20Sopenharmony_ci#include "sysv.h" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* We don't trust the value of 338c2ecf20Sopenharmony_ci sb->sv_sbd2->s_tinode = *sb->sv_sb_total_free_inodes 348c2ecf20Sopenharmony_ci but we nevertheless keep it up to date. */ 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* An inode on disk is considered free if both i_mode == 0 and i_nlink == 0. */ 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* return &sb->sv_sb_fic_inodes[i] = &sbd->s_inode[i]; */ 398c2ecf20Sopenharmony_cistatic inline sysv_ino_t * 408c2ecf20Sopenharmony_cisv_sb_fic_inode(struct super_block * sb, unsigned int i) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci struct sysv_sb_info *sbi = SYSV_SB(sb); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci if (sbi->s_bh1 == sbi->s_bh2) 458c2ecf20Sopenharmony_ci return &sbi->s_sb_fic_inodes[i]; 468c2ecf20Sopenharmony_ci else { 478c2ecf20Sopenharmony_ci /* 512 byte Xenix FS */ 488c2ecf20Sopenharmony_ci unsigned int offset = offsetof(struct xenix_super_block, s_inode[i]); 498c2ecf20Sopenharmony_ci if (offset < 512) 508c2ecf20Sopenharmony_ci return (sysv_ino_t*)(sbi->s_sbd1 + offset); 518c2ecf20Sopenharmony_ci else 528c2ecf20Sopenharmony_ci return (sysv_ino_t*)(sbi->s_sbd2 + offset); 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistruct sysv_inode * 578c2ecf20Sopenharmony_cisysv_raw_inode(struct super_block *sb, unsigned ino, struct buffer_head **bh) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci struct sysv_sb_info *sbi = SYSV_SB(sb); 608c2ecf20Sopenharmony_ci struct sysv_inode *res; 618c2ecf20Sopenharmony_ci int block = sbi->s_firstinodezone + sbi->s_block_base; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci block += (ino-1) >> sbi->s_inodes_per_block_bits; 648c2ecf20Sopenharmony_ci *bh = sb_bread(sb, block); 658c2ecf20Sopenharmony_ci if (!*bh) 668c2ecf20Sopenharmony_ci return NULL; 678c2ecf20Sopenharmony_ci res = (struct sysv_inode *)(*bh)->b_data; 688c2ecf20Sopenharmony_ci return res + ((ino-1) & sbi->s_inodes_per_block_1); 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic int refill_free_cache(struct super_block *sb) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci struct sysv_sb_info *sbi = SYSV_SB(sb); 748c2ecf20Sopenharmony_ci struct buffer_head * bh; 758c2ecf20Sopenharmony_ci struct sysv_inode * raw_inode; 768c2ecf20Sopenharmony_ci int i = 0, ino; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci ino = SYSV_ROOT_INO+1; 798c2ecf20Sopenharmony_ci raw_inode = sysv_raw_inode(sb, ino, &bh); 808c2ecf20Sopenharmony_ci if (!raw_inode) 818c2ecf20Sopenharmony_ci goto out; 828c2ecf20Sopenharmony_ci while (ino <= sbi->s_ninodes) { 838c2ecf20Sopenharmony_ci if (raw_inode->i_mode == 0 && raw_inode->i_nlink == 0) { 848c2ecf20Sopenharmony_ci *sv_sb_fic_inode(sb,i++) = cpu_to_fs16(SYSV_SB(sb), ino); 858c2ecf20Sopenharmony_ci if (i == sbi->s_fic_size) 868c2ecf20Sopenharmony_ci break; 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci if ((ino++ & sbi->s_inodes_per_block_1) == 0) { 898c2ecf20Sopenharmony_ci brelse(bh); 908c2ecf20Sopenharmony_ci raw_inode = sysv_raw_inode(sb, ino, &bh); 918c2ecf20Sopenharmony_ci if (!raw_inode) 928c2ecf20Sopenharmony_ci goto out; 938c2ecf20Sopenharmony_ci } else 948c2ecf20Sopenharmony_ci raw_inode++; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci brelse(bh); 978c2ecf20Sopenharmony_ciout: 988c2ecf20Sopenharmony_ci return i; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_civoid sysv_free_inode(struct inode * inode) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 1048c2ecf20Sopenharmony_ci struct sysv_sb_info *sbi = SYSV_SB(sb); 1058c2ecf20Sopenharmony_ci unsigned int ino; 1068c2ecf20Sopenharmony_ci struct buffer_head * bh; 1078c2ecf20Sopenharmony_ci struct sysv_inode * raw_inode; 1088c2ecf20Sopenharmony_ci unsigned count; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci sb = inode->i_sb; 1118c2ecf20Sopenharmony_ci ino = inode->i_ino; 1128c2ecf20Sopenharmony_ci if (ino <= SYSV_ROOT_INO || ino > sbi->s_ninodes) { 1138c2ecf20Sopenharmony_ci printk("sysv_free_inode: inode 0,1,2 or nonexistent inode\n"); 1148c2ecf20Sopenharmony_ci return; 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci raw_inode = sysv_raw_inode(sb, ino, &bh); 1178c2ecf20Sopenharmony_ci if (!raw_inode) { 1188c2ecf20Sopenharmony_ci printk("sysv_free_inode: unable to read inode block on device " 1198c2ecf20Sopenharmony_ci "%s\n", inode->i_sb->s_id); 1208c2ecf20Sopenharmony_ci return; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci mutex_lock(&sbi->s_lock); 1238c2ecf20Sopenharmony_ci count = fs16_to_cpu(sbi, *sbi->s_sb_fic_count); 1248c2ecf20Sopenharmony_ci if (count < sbi->s_fic_size) { 1258c2ecf20Sopenharmony_ci *sv_sb_fic_inode(sb,count++) = cpu_to_fs16(sbi, ino); 1268c2ecf20Sopenharmony_ci *sbi->s_sb_fic_count = cpu_to_fs16(sbi, count); 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci fs16_add(sbi, sbi->s_sb_total_free_inodes, 1); 1298c2ecf20Sopenharmony_ci dirty_sb(sb); 1308c2ecf20Sopenharmony_ci memset(raw_inode, 0, sizeof(struct sysv_inode)); 1318c2ecf20Sopenharmony_ci mark_buffer_dirty(bh); 1328c2ecf20Sopenharmony_ci mutex_unlock(&sbi->s_lock); 1338c2ecf20Sopenharmony_ci brelse(bh); 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistruct inode * sysv_new_inode(const struct inode * dir, umode_t mode) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci struct super_block *sb = dir->i_sb; 1398c2ecf20Sopenharmony_ci struct sysv_sb_info *sbi = SYSV_SB(sb); 1408c2ecf20Sopenharmony_ci struct inode *inode; 1418c2ecf20Sopenharmony_ci sysv_ino_t ino; 1428c2ecf20Sopenharmony_ci unsigned count; 1438c2ecf20Sopenharmony_ci struct writeback_control wbc = { 1448c2ecf20Sopenharmony_ci .sync_mode = WB_SYNC_NONE 1458c2ecf20Sopenharmony_ci }; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci inode = new_inode(sb); 1488c2ecf20Sopenharmony_ci if (!inode) 1498c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci mutex_lock(&sbi->s_lock); 1528c2ecf20Sopenharmony_ci count = fs16_to_cpu(sbi, *sbi->s_sb_fic_count); 1538c2ecf20Sopenharmony_ci if (count == 0 || (*sv_sb_fic_inode(sb,count-1) == 0)) { 1548c2ecf20Sopenharmony_ci count = refill_free_cache(sb); 1558c2ecf20Sopenharmony_ci if (count == 0) { 1568c2ecf20Sopenharmony_ci iput(inode); 1578c2ecf20Sopenharmony_ci mutex_unlock(&sbi->s_lock); 1588c2ecf20Sopenharmony_ci return ERR_PTR(-ENOSPC); 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci /* Now count > 0. */ 1628c2ecf20Sopenharmony_ci ino = *sv_sb_fic_inode(sb,--count); 1638c2ecf20Sopenharmony_ci *sbi->s_sb_fic_count = cpu_to_fs16(sbi, count); 1648c2ecf20Sopenharmony_ci fs16_add(sbi, sbi->s_sb_total_free_inodes, -1); 1658c2ecf20Sopenharmony_ci dirty_sb(sb); 1668c2ecf20Sopenharmony_ci inode_init_owner(inode, dir, mode); 1678c2ecf20Sopenharmony_ci inode->i_ino = fs16_to_cpu(sbi, ino); 1688c2ecf20Sopenharmony_ci inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); 1698c2ecf20Sopenharmony_ci inode->i_blocks = 0; 1708c2ecf20Sopenharmony_ci memset(SYSV_I(inode)->i_data, 0, sizeof(SYSV_I(inode)->i_data)); 1718c2ecf20Sopenharmony_ci SYSV_I(inode)->i_dir_start_lookup = 0; 1728c2ecf20Sopenharmony_ci insert_inode_hash(inode); 1738c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci sysv_write_inode(inode, &wbc); /* ensure inode not allocated again */ 1768c2ecf20Sopenharmony_ci mark_inode_dirty(inode); /* cleared by sysv_write_inode() */ 1778c2ecf20Sopenharmony_ci /* That's it. */ 1788c2ecf20Sopenharmony_ci mutex_unlock(&sbi->s_lock); 1798c2ecf20Sopenharmony_ci return inode; 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ciunsigned long sysv_count_free_inodes(struct super_block * sb) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci struct sysv_sb_info *sbi = SYSV_SB(sb); 1858c2ecf20Sopenharmony_ci struct buffer_head * bh; 1868c2ecf20Sopenharmony_ci struct sysv_inode * raw_inode; 1878c2ecf20Sopenharmony_ci int ino, count, sb_count; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci mutex_lock(&sbi->s_lock); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci sb_count = fs16_to_cpu(sbi, *sbi->s_sb_total_free_inodes); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (0) 1948c2ecf20Sopenharmony_ci goto trust_sb; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci /* this causes a lot of disk traffic ... */ 1978c2ecf20Sopenharmony_ci count = 0; 1988c2ecf20Sopenharmony_ci ino = SYSV_ROOT_INO+1; 1998c2ecf20Sopenharmony_ci raw_inode = sysv_raw_inode(sb, ino, &bh); 2008c2ecf20Sopenharmony_ci if (!raw_inode) 2018c2ecf20Sopenharmony_ci goto Eio; 2028c2ecf20Sopenharmony_ci while (ino <= sbi->s_ninodes) { 2038c2ecf20Sopenharmony_ci if (raw_inode->i_mode == 0 && raw_inode->i_nlink == 0) 2048c2ecf20Sopenharmony_ci count++; 2058c2ecf20Sopenharmony_ci if ((ino++ & sbi->s_inodes_per_block_1) == 0) { 2068c2ecf20Sopenharmony_ci brelse(bh); 2078c2ecf20Sopenharmony_ci raw_inode = sysv_raw_inode(sb, ino, &bh); 2088c2ecf20Sopenharmony_ci if (!raw_inode) 2098c2ecf20Sopenharmony_ci goto Eio; 2108c2ecf20Sopenharmony_ci } else 2118c2ecf20Sopenharmony_ci raw_inode++; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci brelse(bh); 2148c2ecf20Sopenharmony_ci if (count != sb_count) 2158c2ecf20Sopenharmony_ci goto Einval; 2168c2ecf20Sopenharmony_ciout: 2178c2ecf20Sopenharmony_ci mutex_unlock(&sbi->s_lock); 2188c2ecf20Sopenharmony_ci return count; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ciEinval: 2218c2ecf20Sopenharmony_ci printk("sysv_count_free_inodes: " 2228c2ecf20Sopenharmony_ci "free inode count was %d, correcting to %d\n", 2238c2ecf20Sopenharmony_ci sb_count, count); 2248c2ecf20Sopenharmony_ci if (!sb_rdonly(sb)) { 2258c2ecf20Sopenharmony_ci *sbi->s_sb_total_free_inodes = cpu_to_fs16(SYSV_SB(sb), count); 2268c2ecf20Sopenharmony_ci dirty_sb(sb); 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci goto out; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ciEio: 2318c2ecf20Sopenharmony_ci printk("sysv_count_free_inodes: unable to read inode table\n"); 2328c2ecf20Sopenharmony_citrust_sb: 2338c2ecf20Sopenharmony_ci count = sb_count; 2348c2ecf20Sopenharmony_ci goto out; 2358c2ecf20Sopenharmony_ci} 236