Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 | /* * linux/fs/sysv/ialloc.c * * minix/bitmap.c * Copyright (C) 1991, 1992 Linus Torvalds * * ext/freelists.c * Copyright (C) 1992 Remy Card (card@masi.ibp.fr) * * xenix/alloc.c * Copyright (C) 1992 Doug Evans * * coh/alloc.c * Copyright (C) 1993 Pascal Haible, Bruno Haible * * sysv/ialloc.c * Copyright (C) 1993 Bruno Haible * * This file contains code for allocating/freeing inodes. */ #include <linux/sched.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/sysv_fs.h> #include <linux/stddef.h> #include <linux/stat.h> #include <linux/string.h> #include <linux/locks.h> /* We don't trust the value of sb->sv_sbd2->s_tinode = *sb->sv_sb_total_free_inodes but we nevertheless keep it up to date. */ /* An inode on disk is considered free if both i_mode == 0 and i_nlink == 0. */ /* return &sb->sv_sb_fic_inodes[i] = &sbd->s_inode[i]; */ static inline sysv_ino_t * sv_sb_fic_inode (struct super_block * sb, unsigned int i) { if (sb->sv_bh1 == sb->sv_bh2) return &sb->sv_sb_fic_inodes[i]; else { /* 512 byte Xenix FS */ unsigned int offset = offsetof(struct xenix_super_block, s_inode[i]); if (offset < 512) return (sysv_ino_t*)(sb->sv_sbd1 + offset); else return (sysv_ino_t*)(sb->sv_sbd2 + offset); } } void sysv_free_inode(struct inode * inode) { struct super_block * sb; unsigned int ino; struct buffer_head * bh; struct sysv_inode * raw_inode; if (!inode) return; if (!inode->i_dev) { printk("sysv_free_inode: inode has no device\n"); return; } if (inode->i_count != 1) { printk("sysv_free_inode: inode has count=%d\n", inode->i_count); return; } if (inode->i_nlink) { printk("sysv_free_inode: inode has nlink=%d\n", inode->i_nlink); return; } if (!(sb = inode->i_sb)) { printk("sysv_free_inode: inode on nonexistent device\n"); return; } ino = inode->i_ino; if (ino <= SYSV_ROOT_INO || ino > sb->sv_ninodes) { printk("sysv_free_inode: inode 0,1,2 or nonexistent inode\n"); return; } if (!(bh = sv_bread(sb, inode->i_dev, sb->sv_firstinodezone + ((ino-1) >> sb->sv_inodes_per_block_bits)))) { printk("sysv_free_inode: unable to read inode block on device " "%s\n", kdevname(inode->i_dev)); clear_inode(inode); return; } raw_inode = (struct sysv_inode *) bh->b_data + ((ino-1) & sb->sv_inodes_per_block_1); lock_super(sb); if (*sb->sv_sb_fic_count < sb->sv_fic_size) *sv_sb_fic_inode(sb,(*sb->sv_sb_fic_count)++) = ino; (*sb->sv_sb_total_free_inodes)++; mark_buffer_dirty(sb->sv_bh1, 1); /* super-block has been modified */ if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2, 1); sb->s_dirt = 1; /* and needs time stamp */ memset(raw_inode, 0, sizeof(struct sysv_inode)); mark_buffer_dirty(bh, 1); unlock_super(sb); brelse(bh); clear_inode(inode); } struct inode * sysv_new_inode(const struct inode * dir) { struct inode * inode; struct super_block * sb; struct buffer_head * bh; struct sysv_inode * raw_inode; int i,j,ino,block; if (!dir || !(inode = get_empty_inode())) return NULL; sb = dir->i_sb; inode->i_sb = sb; inode->i_flags = 0; lock_super(sb); /* protect against task switches */ if ((*sb->sv_sb_fic_count == 0) || (*sv_sb_fic_inode(sb,(*sb->sv_sb_fic_count)-1) == 0) /* Applies only to SystemV2 FS */ ) { /* Rebuild cache of free inodes: */ /* i : index into cache slot being filled */ /* ino : inode we are trying */ /* block : firstinodezone + (ino-1)/inodes_per_block */ /* j : (ino-1)%inodes_per_block */ /* bh : buffer for block */ /* raw_inode : pointer to inode ino in the block */ for (i = 0, ino = SYSV_ROOT_INO+1, block = sb->sv_firstinodezone, j = SYSV_ROOT_INO ; i < sb->sv_fic_size && block < sb->sv_firstdatazone ; block++, j = 0) { if (!(bh = sv_bread(sb, sb->s_dev, block))) { printk("sysv_new_inode: unable to read inode table\n"); break; /* go with what we've got */ /* FIXME: Perhaps try the next block? */ } raw_inode = (struct sysv_inode *) bh->b_data + j; for (; j < sb->sv_inodes_per_block && i < sb->sv_fic_size; ino++, j++, raw_inode++) { if (raw_inode->i_mode == 0 && raw_inode->i_nlink == 0) *sv_sb_fic_inode(sb,i++) = ino; } brelse(bh); } if (i == 0) { iput(inode); unlock_super(sb); return NULL; /* no inodes available */ } *sb->sv_sb_fic_count = i; } /* Now *sb->sv_sb_fic_count > 0. */ ino = *sv_sb_fic_inode(sb,--(*sb->sv_sb_fic_count)); mark_buffer_dirty(sb->sv_bh1, 1); /* super-block has been modified */ if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2, 1); sb->s_dirt = 1; /* and needs time stamp */ inode->i_count = 1; inode->i_nlink = 1; inode->i_dev = sb->s_dev; inode->i_uid = current->fsuid; inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; inode->i_ino = ino; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; inode->i_op = NULL; inode->i_blocks = inode->i_blksize = 0; insert_inode_hash(inode); mark_inode_dirty(inode); /* Change directory entry: */ inode->i_mode = 0; /* for sysv_write_inode() */ inode->i_size = 0; /* ditto */ sysv_write_inode(inode); /* ensure inode not allocated again */ /* FIXME: caller may call this too. */ mark_inode_dirty(inode); /* cleared by sysv_write_inode() */ /* That's it. */ (*sb->sv_sb_total_free_inodes)--; mark_buffer_dirty(sb->sv_bh2, 1); /* super-block has been modified again */ sb->s_dirt = 1; /* and needs time stamp again */ unlock_super(sb); return inode; } unsigned long sysv_count_free_inodes(struct super_block * sb) { #if 1 /* test */ struct buffer_head * bh; struct sysv_inode * raw_inode; int j,block,count; /* this causes a lot of disk traffic ... */ count = 0; lock_super(sb); /* i : index into cache slot being filled */ /* ino : inode we are trying */ /* block : firstinodezone + (ino-1)/inodes_per_block */ /* j : (ino-1)%inodes_per_block */ /* bh : buffer for block */ /* raw_inode : pointer to inode ino in the block */ for (block = sb->sv_firstinodezone, j = SYSV_ROOT_INO ; block < sb->sv_firstdatazone ; block++, j = 0) { if (!(bh = sv_bread(sb, sb->s_dev, block))) { printk("sysv_count_free_inodes: unable to read inode table\n"); break; /* go with what we've got */ /* FIXME: Perhaps try the next block? */ } raw_inode = (struct sysv_inode *) bh->b_data + j; for (; j < sb->sv_inodes_per_block ; j++, raw_inode++) if (raw_inode->i_mode == 0 && raw_inode->i_nlink == 0) count++; brelse(bh); } if (count != *sb->sv_sb_total_free_inodes) { printk("sysv_count_free_inodes: free inode count was %d, correcting to %d\n",(short)(*sb->sv_sb_total_free_inodes),count); if (!(sb->s_flags & MS_RDONLY)) { *sb->sv_sb_total_free_inodes = count; mark_buffer_dirty(sb->sv_bh2, 1); /* super-block has been modified */ sb->s_dirt = 1; /* and needs time stamp */ } } unlock_super(sb); return count; #else return *sb->sv_sb_total_free_inodes; #endif } |