0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023 #include <linux/buffer_head.h>
0024 #include <linux/string.h>
0025 #include "sysv.h"
0026
0027
0028
0029
0030
0031 static inline sysv_zone_t *get_chunk(struct super_block *sb, struct buffer_head *bh)
0032 {
0033 char *bh_data = bh->b_data;
0034
0035 if (SYSV_SB(sb)->s_type == FSTYPE_SYSV4)
0036 return (sysv_zone_t*)(bh_data+4);
0037 else
0038 return (sysv_zone_t*)(bh_data+2);
0039 }
0040
0041
0042
0043 void sysv_free_block(struct super_block * sb, sysv_zone_t nr)
0044 {
0045 struct sysv_sb_info * sbi = SYSV_SB(sb);
0046 struct buffer_head * bh;
0047 sysv_zone_t *blocks = sbi->s_bcache;
0048 unsigned count;
0049 unsigned block = fs32_to_cpu(sbi, nr);
0050
0051
0052
0053
0054
0055
0056 if (sbi->s_type == FSTYPE_AFS)
0057 return;
0058
0059 if (block < sbi->s_firstdatazone || block >= sbi->s_nzones) {
0060 printk("sysv_free_block: trying to free block not in datazone\n");
0061 return;
0062 }
0063
0064 mutex_lock(&sbi->s_lock);
0065 count = fs16_to_cpu(sbi, *sbi->s_bcache_count);
0066
0067 if (count > sbi->s_flc_size) {
0068 printk("sysv_free_block: flc_count > flc_size\n");
0069 mutex_unlock(&sbi->s_lock);
0070 return;
0071 }
0072
0073
0074
0075
0076 if (count == sbi->s_flc_size || count == 0) {
0077 block += sbi->s_block_base;
0078 bh = sb_getblk(sb, block);
0079 if (!bh) {
0080 printk("sysv_free_block: getblk() failed\n");
0081 mutex_unlock(&sbi->s_lock);
0082 return;
0083 }
0084 memset(bh->b_data, 0, sb->s_blocksize);
0085 *(__fs16*)bh->b_data = cpu_to_fs16(sbi, count);
0086 memcpy(get_chunk(sb,bh), blocks, count * sizeof(sysv_zone_t));
0087 mark_buffer_dirty(bh);
0088 set_buffer_uptodate(bh);
0089 brelse(bh);
0090 count = 0;
0091 }
0092 sbi->s_bcache[count++] = nr;
0093
0094 *sbi->s_bcache_count = cpu_to_fs16(sbi, count);
0095 fs32_add(sbi, sbi->s_free_blocks, 1);
0096 dirty_sb(sb);
0097 mutex_unlock(&sbi->s_lock);
0098 }
0099
0100 sysv_zone_t sysv_new_block(struct super_block * sb)
0101 {
0102 struct sysv_sb_info *sbi = SYSV_SB(sb);
0103 unsigned int block;
0104 sysv_zone_t nr;
0105 struct buffer_head * bh;
0106 unsigned count;
0107
0108 mutex_lock(&sbi->s_lock);
0109 count = fs16_to_cpu(sbi, *sbi->s_bcache_count);
0110
0111 if (count == 0)
0112 goto Enospc;
0113 nr = sbi->s_bcache[--count];
0114 if (nr == 0)
0115 goto Enospc;
0116
0117 block = fs32_to_cpu(sbi, nr);
0118
0119 *sbi->s_bcache_count = cpu_to_fs16(sbi, count);
0120
0121 if (block < sbi->s_firstdatazone || block >= sbi->s_nzones) {
0122 printk("sysv_new_block: new block %d is not in data zone\n",
0123 block);
0124 goto Enospc;
0125 }
0126
0127 if (count == 0) {
0128 unsigned count;
0129
0130 block += sbi->s_block_base;
0131 if (!(bh = sb_bread(sb, block))) {
0132 printk("sysv_new_block: cannot read free-list block\n");
0133
0134 *sbi->s_bcache_count = cpu_to_fs16(sbi, 1);
0135 goto Enospc;
0136 }
0137 count = fs16_to_cpu(sbi, *(__fs16*)bh->b_data);
0138 if (count > sbi->s_flc_size) {
0139 printk("sysv_new_block: free-list block with >flc_size entries\n");
0140 brelse(bh);
0141 goto Enospc;
0142 }
0143 *sbi->s_bcache_count = cpu_to_fs16(sbi, count);
0144 memcpy(sbi->s_bcache, get_chunk(sb, bh),
0145 count * sizeof(sysv_zone_t));
0146 brelse(bh);
0147 }
0148
0149 fs32_add(sbi, sbi->s_free_blocks, -1);
0150 dirty_sb(sb);
0151 mutex_unlock(&sbi->s_lock);
0152 return nr;
0153
0154 Enospc:
0155 mutex_unlock(&sbi->s_lock);
0156 return 0;
0157 }
0158
0159 unsigned long sysv_count_free_blocks(struct super_block * sb)
0160 {
0161 struct sysv_sb_info * sbi = SYSV_SB(sb);
0162 int sb_count;
0163 int count;
0164 struct buffer_head * bh = NULL;
0165 sysv_zone_t *blocks;
0166 unsigned block;
0167 int n;
0168
0169
0170
0171
0172
0173
0174 if (sbi->s_type == FSTYPE_AFS)
0175 return 0;
0176
0177 mutex_lock(&sbi->s_lock);
0178 sb_count = fs32_to_cpu(sbi, *sbi->s_free_blocks);
0179
0180 if (0)
0181 goto trust_sb;
0182
0183
0184 count = 0;
0185 n = fs16_to_cpu(sbi, *sbi->s_bcache_count);
0186 blocks = sbi->s_bcache;
0187 while (1) {
0188 sysv_zone_t zone;
0189 if (n > sbi->s_flc_size)
0190 goto E2big;
0191 zone = 0;
0192 while (n && (zone = blocks[--n]) != 0)
0193 count++;
0194 if (zone == 0)
0195 break;
0196
0197 block = fs32_to_cpu(sbi, zone);
0198 if (bh)
0199 brelse(bh);
0200
0201 if (block < sbi->s_firstdatazone || block >= sbi->s_nzones)
0202 goto Einval;
0203 block += sbi->s_block_base;
0204 bh = sb_bread(sb, block);
0205 if (!bh)
0206 goto Eio;
0207 n = fs16_to_cpu(sbi, *(__fs16*)bh->b_data);
0208 blocks = get_chunk(sb, bh);
0209 }
0210 if (bh)
0211 brelse(bh);
0212 if (count != sb_count)
0213 goto Ecount;
0214 done:
0215 mutex_unlock(&sbi->s_lock);
0216 return count;
0217
0218 Einval:
0219 printk("sysv_count_free_blocks: new block %d is not in data zone\n",
0220 block);
0221 goto trust_sb;
0222 Eio:
0223 printk("sysv_count_free_blocks: cannot read free-list block\n");
0224 goto trust_sb;
0225 E2big:
0226 printk("sysv_count_free_blocks: >flc_size entries in free-list block\n");
0227 if (bh)
0228 brelse(bh);
0229 trust_sb:
0230 count = sb_count;
0231 goto done;
0232 Ecount:
0233 printk("sysv_count_free_blocks: free block count was %d, "
0234 "correcting to %d\n", sb_count, count);
0235 if (!sb_rdonly(sb)) {
0236 *sbi->s_free_blocks = cpu_to_fs32(sbi, count);
0237 dirty_sb(sb);
0238 }
0239 goto done;
0240 }