123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- #include "fs.h"
- #include <string.h>
- #include <assert.h>
- #include <sys/param.h>
- #include "buf.h"
- #include "inode.h"
- #include "super.h"
- static void wr_indir(struct buf *bp, int index, zone_t zone);
- static int empty_indir(struct buf *, struct super_block *);
- int write_map(rip, position, new_zone, op)
- struct inode *rip;
- off_t position;
- zone_t new_zone;
- int op;
- {
- int scale, ind_ex = 0, new_ind, new_dbl,
- zones, nr_indirects, single, zindex, ex;
- zone_t z, z1, z2 = NO_ZONE, old_zone;
- register block_t b;
- long excess, zone;
- struct buf *bp_dindir = NULL, *bp = NULL;
- IN_MARKDIRTY(rip);
- scale = rip->i_sp->s_log_zone_size;
-
- zone = (position/rip->i_sp->s_block_size) >> scale;
- zones = rip->i_ndzones;
- nr_indirects = rip->i_nindirs;
-
- if (zone < zones) {
- zindex = (int) zone;
- if(rip->i_zone[zindex] != NO_ZONE && (op & WMAP_FREE)) {
- free_zone(rip->i_dev, rip->i_zone[zindex]);
- rip->i_zone[zindex] = NO_ZONE;
- } else {
- rip->i_zone[zindex] = new_zone;
- }
- return(OK);
- }
-
- excess = zone - zones;
- new_ind = FALSE;
- new_dbl = FALSE;
- if (excess < nr_indirects) {
-
- z1 = rip->i_zone[zones];
- single = TRUE;
- } else {
-
- if ( (z2 = z = rip->i_zone[zones+1]) == NO_ZONE &&
- !(op & WMAP_FREE)) {
-
- if ( (z = alloc_zone(rip->i_dev, rip->i_zone[0])) == NO_ZONE)
- return(err_code);
- rip->i_zone[zones+1] = z;
- new_dbl = TRUE;
- }
-
- excess -= nr_indirects;
- ind_ex = (int) (excess / nr_indirects);
- excess = excess % nr_indirects;
- if (ind_ex >= nr_indirects) return(EFBIG);
- if(z == NO_ZONE && (op & WMAP_FREE)) {
-
- z1 = NO_ZONE;
- } else {
- b = (block_t) z << scale;
- bp_dindir = get_block(rip->i_dev, b,
- (new_dbl?NO_READ:NORMAL));
- if (new_dbl) zero_block(bp_dindir);
- z1 = rd_indir(bp_dindir, ind_ex);
- }
- single = FALSE;
- }
-
- if (z1 == NO_ZONE && !(op & WMAP_FREE)) {
- z1 = alloc_zone(rip->i_dev, rip->i_zone[0]);
- if (single)
- rip->i_zone[zones] = z1;
- else
- wr_indir(bp_dindir, ind_ex, z1);
- new_ind = TRUE;
-
- if (bp_dindir != NULL) MARKDIRTY(bp_dindir);
- if (z1 == NO_ZONE) {
-
- put_block(bp_dindir);
- return(err_code);
- }
- }
-
- if(z1 != NO_ZONE) {
- ex = (int) excess;
- b = (block_t) z1 << scale;
- bp = get_block(rip->i_dev, b, (new_ind ? NO_READ : NORMAL) );
- if (new_ind) zero_block(bp);
- if(op & WMAP_FREE) {
- if((old_zone = rd_indir(bp, ex)) != NO_ZONE) {
- free_zone(rip->i_dev, old_zone);
- wr_indir(bp, ex, NO_ZONE);
- }
-
- if(empty_indir(bp, rip->i_sp)) {
- free_zone(rip->i_dev, z1);
- z1 = NO_ZONE;
-
- if(single) {
- rip->i_zone[zones] = z1;
- } else {
- wr_indir(bp_dindir, ind_ex, z1);
- MARKDIRTY(bp_dindir);
- }
- }
- } else {
- wr_indir(bp, ex, new_zone);
- }
-
- if(z1 != NO_ZONE) MARKDIRTY(bp);
- put_block(bp);
- }
-
- if(z1 == NO_ZONE && !single && z2 != NO_ZONE &&
- empty_indir(bp_dindir, rip->i_sp)) {
- free_zone(rip->i_dev, z2);
- rip->i_zone[zones+1] = NO_ZONE;
- }
- put_block(bp_dindir);
- return(OK);
- }
- static void wr_indir(bp, index, zone)
- struct buf *bp;
- int index;
- zone_t zone;
- {
- struct super_block *sp;
- if(bp == NULL)
- panic("wr_indir() on NULL");
- sp = &superblock;
-
- assert(sp->s_version == V3);
- b_v2_ind(bp)[index] = (zone_t) conv4(sp->s_native, (long) zone);
- }
- static int empty_indir(bp, sb)
- struct buf *bp;
- struct super_block *sb;
- {
- unsigned int i;
- for(i = 0; i < V2_INDIRECTS(sb->s_block_size); i++)
- if( b_v2_ind(bp)[i] != NO_ZONE)
- return(0);
- return(1);
- }
- void clear_zone(rip, pos, flag)
- register struct inode *rip;
- off_t __unused pos;
- int __unused flag;
- {
- int scale;
-
- scale = rip->i_sp->s_log_zone_size;
- assert(scale == 0);
- return;
- }
- struct buf *new_block(rip, position)
- register struct inode *rip;
- off_t position;
- {
- struct buf *bp;
- block_t b, base_block;
- zone_t z;
- zone_t zone_size;
- int scale, r;
-
- if ( (b = read_map(rip, position, 0)) == NO_BLOCK) {
- if (rip->i_zsearch == NO_ZONE) {
-
- if ( (z = rip->i_zone[0]) == NO_ZONE) {
-
- z = (zone_t) rip->i_sp->s_firstdatazone;
- }
- } else {
-
- z = rip->i_zsearch;
- }
- if ( (z = alloc_zone(rip->i_dev, z)) == NO_ZONE) return(NULL);
- rip->i_zsearch = z;
- if ( (r = write_map(rip, position, z, 0)) != OK) {
- free_zone(rip->i_dev, z);
- err_code = r;
- return(NULL);
- }
-
- if ( position != rip->i_size) clear_zone(rip, position, 1);
- scale = rip->i_sp->s_log_zone_size;
- base_block = (block_t) z << scale;
- zone_size = (zone_t) rip->i_sp->s_block_size << scale;
- b = base_block + (block_t)((position % zone_size)/rip->i_sp->s_block_size);
- }
- r = lmfs_get_block_ino(&bp, rip->i_dev, b, NO_READ, rip->i_num,
- rounddown(position, rip->i_sp->s_block_size));
- if (r != OK)
- panic("MFS: error getting block (%llu,%u): %d", rip->i_dev, b, r);
- zero_block(bp);
- return(bp);
- }
- void zero_block(bp)
- register struct buf *bp;
- {
- ASSERT(bp->data);
- memset(b_data(bp), 0, lmfs_fs_block_size());
- MARKDIRTY(bp);
- }
|