00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "fs.h"
00011 #include <string.h>
00012 #include "buf.h"
00013 #include "file.h"
00014 #include "fproc.h"
00015 #include "inode.h"
00016 #include "super.h"
00017
00018 FORWARD _PROTOTYPE( void wr_indir, (struct buf *bp, int index, zone_t zone) );
00019 FORWARD _PROTOTYPE( int empty_indir, (struct buf *, struct super_block *) );
00020
00021
00022
00023
00024 PUBLIC int do_write()
00025 {
00026
00027
00028 return(read_write(WRITING));
00029 }
00030
00031
00032
00033
00034 PUBLIC int write_map(rip, position, new_zone, op)
00035 struct inode *rip;
00036 off_t position;
00037 zone_t new_zone;
00038 int op;
00039 {
00040
00041
00042
00043
00044
00045
00046
00047
00048 int scale, ind_ex, new_ind, new_dbl, zones, nr_indirects, single, zindex, ex;
00049 zone_t z, z1, z2 = NO_ZONE, old_zone;
00050 register block_t b;
00051 long excess, zone;
00052 struct buf *bp_dindir = NIL_BUF, *bp = NIL_BUF;
00053
00054 rip->i_dirt = DIRTY;
00055 scale = rip->i_sp->s_log_zone_size;
00056
00057 zone = (position/rip->i_sp->s_block_size) >> scale;
00058 zones = rip->i_ndzones;
00059 nr_indirects = rip->i_nindirs;
00060
00061
00062 if (zone < zones) {
00063 zindex = (int) zone;
00064 if(rip->i_zone[zindex] != NO_ZONE && (op & WMAP_FREE)) {
00065 free_zone(rip->i_dev, rip->i_zone[zindex]);
00066 rip->i_zone[zindex] = NO_ZONE;
00067 } else {
00068 rip->i_zone[zindex] = new_zone;
00069 }
00070 return(OK);
00071 }
00072
00073
00074 excess = zone - zones;
00075 new_ind = FALSE;
00076 new_dbl = FALSE;
00077
00078 if (excess < nr_indirects) {
00079
00080 z1 = rip->i_zone[zones];
00081 single = TRUE;
00082 } else {
00083
00084 if ( (z2 = z = rip->i_zone[zones+1]) == NO_ZONE &&
00085 !(op & WMAP_FREE)) {
00086
00087 if ( (z = alloc_zone(rip->i_dev, rip->i_zone[0])) == NO_ZONE)
00088 return(err_code);
00089 rip->i_zone[zones+1] = z;
00090 new_dbl = TRUE;
00091 }
00092
00093
00094
00095
00096
00097 excess -= nr_indirects;
00098 ind_ex = (int) (excess / nr_indirects);
00099 excess = excess % nr_indirects;
00100 if (ind_ex >= nr_indirects) return(EFBIG);
00101
00102 if(z == NO_ZONE) {
00103
00104
00105
00106 z1 = NO_ZONE;
00107 } else {
00108 b = (block_t) z << scale;
00109 bp_dindir = get_block(rip->i_dev, b, (new_dbl?NO_READ:NORMAL));
00110 if (new_dbl) zero_block(bp_dindir);
00111 z1 = rd_indir(bp_dindir, ind_ex);
00112 }
00113 single = FALSE;
00114 }
00115
00116
00117
00118
00119
00120 if (z1 == NO_ZONE && !(op & WMAP_FREE)) {
00121 z1 = alloc_zone(rip->i_dev, rip->i_zone[0]);
00122 if (single)
00123 rip->i_zone[zones] = z1;
00124 else
00125 wr_indir(bp_dindir, ind_ex, z1);
00126
00127 new_ind = TRUE;
00128
00129 if (bp_dindir != NIL_BUF) bp_dindir->b_dirt = DIRTY;
00130 if (z1 == NO_ZONE) {
00131
00132 put_block(bp_dindir, INDIRECT_BLOCK);
00133 return(err_code);
00134 }
00135 }
00136
00137
00138
00139
00140 if(z1 != NO_ZONE) {
00141 ex = (int) excess;
00142 b = (block_t) z1 << scale;
00143 bp = get_block(rip->i_dev, b, (new_ind ? NO_READ : NORMAL) );
00144 if (new_ind) zero_block(bp);
00145 if(op & WMAP_FREE) {
00146 if((old_zone = rd_indir(bp, ex)) != NO_ZONE) {
00147 free_zone(rip->i_dev, old_zone);
00148 wr_indir(bp, ex, NO_ZONE);
00149 }
00150
00151
00152
00153
00154 if(empty_indir(bp, rip->i_sp)) {
00155 free_zone(rip->i_dev, z1);
00156 z1 = NO_ZONE;
00157
00158
00159
00160
00161 if(single) {
00162 rip->i_zone[zones] = z1;
00163 } else {
00164 wr_indir(bp_dindir, ind_ex, z1);
00165 bp_dindir->b_dirt = DIRTY;
00166 }
00167 }
00168 } else {
00169 wr_indir(bp, ex, new_zone);
00170 }
00171 bp->b_dirt = DIRTY;
00172 put_block(bp, INDIRECT_BLOCK);
00173 }
00174
00175
00176
00177
00178 if(z1 == NO_ZONE && !single && empty_indir(bp_dindir, rip->i_sp) &&
00179 z2 != NO_ZONE) {
00180 free_zone(rip->i_dev, z2);
00181 rip->i_zone[zones+1] = NO_ZONE;
00182 }
00183
00184 put_block(bp_dindir, INDIRECT_BLOCK);
00185
00186 return(OK);
00187 }
00188
00189
00190
00191
00192 PRIVATE void wr_indir(bp, index, zone)
00193 struct buf *bp;
00194 int index;
00195 zone_t zone;
00196 {
00197
00198
00199 struct super_block *sp;
00200
00201 if(bp == NIL_BUF)
00202 panic(__FILE__, "wr_indir() on NIL_BUF", NO_NUM);
00203
00204 sp = get_super(bp->b_dev);
00205
00206
00207 if (sp->s_version == V1)
00208 bp->b_v1_ind[index] = (zone1_t) conv2(sp->s_native, (int) zone);
00209 else
00210 bp->b_v2_ind[index] = (zone_t) conv4(sp->s_native, (long) zone);
00211 }
00212
00213
00214
00215
00216 PRIVATE int empty_indir(bp, sb)
00217 struct buf *bp;
00218 struct super_block *sb;
00219 {
00220
00221
00222
00223 int i;
00224 if(sb->s_version == V1) {
00225 for(i = 0; i < V1_INDIRECTS; i++)
00226 if(bp->b_v1_ind[i] != NO_ZONE)
00227 return 0;
00228 } else {
00229 for(i = 0; i < V2_INDIRECTS(sb->s_block_size); i++)
00230 if(bp->b_v2_ind[i] != NO_ZONE)
00231 return 0;
00232 }
00233
00234 return 1;
00235 }
00236
00237
00238
00239
00240 PUBLIC void clear_zone(rip, pos, flag)
00241 register struct inode *rip;
00242 off_t pos;
00243 int flag;
00244 {
00245
00246
00247
00248
00249
00250 register struct buf *bp;
00251 register block_t b, blo, bhi;
00252 register off_t next;
00253 register int scale;
00254 register zone_t zone_size;
00255
00256
00257 scale = rip->i_sp->s_log_zone_size;
00258 if (scale == 0) return;
00259
00260 zone_size = (zone_t) rip->i_sp->s_block_size << scale;
00261 if (flag == 1) pos = (pos/zone_size) * zone_size;
00262 next = pos + rip->i_sp->s_block_size - 1;
00263
00264
00265 if (next/zone_size != pos/zone_size) return;
00266 if ( (blo = read_map(rip, next)) == NO_BLOCK) return;
00267 bhi = ( ((blo>>scale)+1) << scale) - 1;
00268
00269
00270 for (b = blo; b <= bhi; b++) {
00271 bp = get_block(rip->i_dev, b, NO_READ);
00272 zero_block(bp);
00273 put_block(bp, FULL_DATA_BLOCK);
00274 }
00275 }
00276
00277
00278
00279
00280 PUBLIC struct buf *new_block(rip, position)
00281 register struct inode *rip;
00282 off_t position;
00283 {
00284
00285
00286
00287
00288
00289 register struct buf *bp;
00290 block_t b, base_block;
00291 zone_t z;
00292 zone_t zone_size;
00293 int scale, r;
00294 struct super_block *sp;
00295
00296
00297 if ( (b = read_map(rip, position)) == NO_BLOCK) {
00298
00299
00300
00301
00302
00303 if (rip->i_zone[0] == NO_ZONE) {
00304 sp = rip->i_sp;
00305 z = sp->s_firstdatazone;
00306 } else {
00307 z = rip->i_zone[0];
00308 }
00309 if ( (z = alloc_zone(rip->i_dev, z)) == NO_ZONE) return(NIL_BUF);
00310 if ( (r = write_map(rip, position, z, 0)) != OK) {
00311 free_zone(rip->i_dev, z);
00312 err_code = r;
00313 return(NIL_BUF);
00314 }
00315
00316
00317 if ( position != rip->i_size) clear_zone(rip, position, 1);
00318 scale = rip->i_sp->s_log_zone_size;
00319 base_block = (block_t) z << scale;
00320 zone_size = (zone_t) rip->i_sp->s_block_size << scale;
00321 b = base_block + (block_t)((position % zone_size)/rip->i_sp->s_block_size);
00322 }
00323
00324 bp = get_block(rip->i_dev, b, NO_READ);
00325 zero_block(bp);
00326 return(bp);
00327 }
00328
00329
00330
00331
00332 PUBLIC void zero_block(bp)
00333 register struct buf *bp;
00334 {
00335
00336 memset(bp->b_data, 0, _MAX_BLOCK_SIZE);
00337 bp->b_dirt = DIRTY;
00338 }