236 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * linux/fs/sysv/ialloc.c4 *5 * minix/bitmap.c6 * Copyright (C) 1991, 1992 Linus Torvalds7 *8 * ext/freelists.c9 * Copyright (C) 1992 Remy Card (card@masi.ibp.fr)10 *11 * xenix/alloc.c12 * Copyright (C) 1992 Doug Evans13 *14 * coh/alloc.c15 * Copyright (C) 1993 Pascal Haible, Bruno Haible16 *17 * sysv/ialloc.c18 * Copyright (C) 1993 Bruno Haible19 *20 * This file contains code for allocating/freeing inodes.21 */22 23#include <linux/kernel.h>24#include <linux/stddef.h>25#include <linux/sched.h>26#include <linux/stat.h>27#include <linux/string.h>28#include <linux/buffer_head.h>29#include <linux/writeback.h>30#include "sysv.h"31 32/* We don't trust the value of33 sb->sv_sbd2->s_tinode = *sb->sv_sb_total_free_inodes34 but we nevertheless keep it up to date. */35 36/* An inode on disk is considered free if both i_mode == 0 and i_nlink == 0. */37 38/* return &sb->sv_sb_fic_inodes[i] = &sbd->s_inode[i]; */39static inline sysv_ino_t *40sv_sb_fic_inode(struct super_block * sb, unsigned int i)41{42 struct sysv_sb_info *sbi = SYSV_SB(sb);43 44 if (sbi->s_bh1 == sbi->s_bh2)45 return &sbi->s_sb_fic_inodes[i];46 else {47 /* 512 byte Xenix FS */48 unsigned int offset = offsetof(struct xenix_super_block, s_inode[i]);49 if (offset < 512)50 return (sysv_ino_t*)(sbi->s_sbd1 + offset);51 else52 return (sysv_ino_t*)(sbi->s_sbd2 + offset);53 }54}55 56struct sysv_inode *57sysv_raw_inode(struct super_block *sb, unsigned ino, struct buffer_head **bh)58{59 struct sysv_sb_info *sbi = SYSV_SB(sb);60 struct sysv_inode *res;61 int block = sbi->s_firstinodezone + sbi->s_block_base;62 63 block += (ino-1) >> sbi->s_inodes_per_block_bits;64 *bh = sb_bread(sb, block);65 if (!*bh)66 return NULL;67 res = (struct sysv_inode *)(*bh)->b_data;68 return res + ((ino-1) & sbi->s_inodes_per_block_1);69}70 71static int refill_free_cache(struct super_block *sb)72{73 struct sysv_sb_info *sbi = SYSV_SB(sb);74 struct buffer_head * bh;75 struct sysv_inode * raw_inode;76 int i = 0, ino;77 78 ino = SYSV_ROOT_INO+1;79 raw_inode = sysv_raw_inode(sb, ino, &bh);80 if (!raw_inode)81 goto out;82 while (ino <= sbi->s_ninodes) {83 if (raw_inode->i_mode == 0 && raw_inode->i_nlink == 0) {84 *sv_sb_fic_inode(sb,i++) = cpu_to_fs16(SYSV_SB(sb), ino);85 if (i == sbi->s_fic_size)86 break;87 }88 if ((ino++ & sbi->s_inodes_per_block_1) == 0) {89 brelse(bh);90 raw_inode = sysv_raw_inode(sb, ino, &bh);91 if (!raw_inode)92 goto out;93 } else94 raw_inode++;95 }96 brelse(bh);97out:98 return i;99}100 101void sysv_free_inode(struct inode * inode)102{103 struct super_block *sb = inode->i_sb;104 struct sysv_sb_info *sbi = SYSV_SB(sb);105 unsigned int ino;106 struct buffer_head * bh;107 struct sysv_inode * raw_inode;108 unsigned count;109 110 sb = inode->i_sb;111 ino = inode->i_ino;112 if (ino <= SYSV_ROOT_INO || ino > sbi->s_ninodes) {113 printk("sysv_free_inode: inode 0,1,2 or nonexistent inode\n");114 return;115 }116 raw_inode = sysv_raw_inode(sb, ino, &bh);117 if (!raw_inode) {118 printk("sysv_free_inode: unable to read inode block on device "119 "%s\n", inode->i_sb->s_id);120 return;121 }122 mutex_lock(&sbi->s_lock);123 count = fs16_to_cpu(sbi, *sbi->s_sb_fic_count);124 if (count < sbi->s_fic_size) {125 *sv_sb_fic_inode(sb,count++) = cpu_to_fs16(sbi, ino);126 *sbi->s_sb_fic_count = cpu_to_fs16(sbi, count);127 }128 fs16_add(sbi, sbi->s_sb_total_free_inodes, 1);129 dirty_sb(sb);130 memset(raw_inode, 0, sizeof(struct sysv_inode));131 mark_buffer_dirty(bh);132 mutex_unlock(&sbi->s_lock);133 brelse(bh);134}135 136struct inode * sysv_new_inode(const struct inode * dir, umode_t mode)137{138 struct super_block *sb = dir->i_sb;139 struct sysv_sb_info *sbi = SYSV_SB(sb);140 struct inode *inode;141 sysv_ino_t ino;142 unsigned count;143 struct writeback_control wbc = {144 .sync_mode = WB_SYNC_NONE145 };146 147 inode = new_inode(sb);148 if (!inode)149 return ERR_PTR(-ENOMEM);150 151 mutex_lock(&sbi->s_lock);152 count = fs16_to_cpu(sbi, *sbi->s_sb_fic_count);153 if (count == 0 || (*sv_sb_fic_inode(sb,count-1) == 0)) {154 count = refill_free_cache(sb);155 if (count == 0) {156 iput(inode);157 mutex_unlock(&sbi->s_lock);158 return ERR_PTR(-ENOSPC);159 }160 }161 /* Now count > 0. */162 ino = *sv_sb_fic_inode(sb,--count);163 *sbi->s_sb_fic_count = cpu_to_fs16(sbi, count);164 fs16_add(sbi, sbi->s_sb_total_free_inodes, -1);165 dirty_sb(sb);166 inode_init_owner(&nop_mnt_idmap, inode, dir, mode);167 inode->i_ino = fs16_to_cpu(sbi, ino);168 simple_inode_init_ts(inode);169 inode->i_blocks = 0;170 memset(SYSV_I(inode)->i_data, 0, sizeof(SYSV_I(inode)->i_data));171 SYSV_I(inode)->i_dir_start_lookup = 0;172 insert_inode_hash(inode);173 mark_inode_dirty(inode);174 175 sysv_write_inode(inode, &wbc); /* ensure inode not allocated again */176 mark_inode_dirty(inode); /* cleared by sysv_write_inode() */177 /* That's it. */178 mutex_unlock(&sbi->s_lock);179 return inode;180}181 182unsigned long sysv_count_free_inodes(struct super_block * sb)183{184 struct sysv_sb_info *sbi = SYSV_SB(sb);185 struct buffer_head * bh;186 struct sysv_inode * raw_inode;187 int ino, count, sb_count;188 189 mutex_lock(&sbi->s_lock);190 191 sb_count = fs16_to_cpu(sbi, *sbi->s_sb_total_free_inodes);192 193 if (0)194 goto trust_sb;195 196 /* this causes a lot of disk traffic ... */197 count = 0;198 ino = SYSV_ROOT_INO+1;199 raw_inode = sysv_raw_inode(sb, ino, &bh);200 if (!raw_inode)201 goto Eio;202 while (ino <= sbi->s_ninodes) {203 if (raw_inode->i_mode == 0 && raw_inode->i_nlink == 0)204 count++;205 if ((ino++ & sbi->s_inodes_per_block_1) == 0) {206 brelse(bh);207 raw_inode = sysv_raw_inode(sb, ino, &bh);208 if (!raw_inode)209 goto Eio;210 } else211 raw_inode++;212 }213 brelse(bh);214 if (count != sb_count)215 goto Einval;216out:217 mutex_unlock(&sbi->s_lock);218 return count;219 220Einval:221 printk("sysv_count_free_inodes: "222 "free inode count was %d, correcting to %d\n",223 sb_count, count);224 if (!sb_rdonly(sb)) {225 *sbi->s_sb_total_free_inodes = cpu_to_fs16(SYSV_SB(sb), count);226 dirty_sb(sb);227 }228 goto out;229 230Eio:231 printk("sysv_count_free_inodes: unable to read inode table\n");232trust_sb:233 count = sb_count;234 goto out;235}236