~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Minix Cross Reference
Minix/fs/write.c


  1 /* This file is the counterpart of "read.c".  It contains the code for writing
  2  * insofar as this is not contained in read_write().
  3  *
  4  * The entry points into this file are
  5  *   do_write:     call read_write to perform the WRITE system call
  6  *   clear_zone:   erase a zone in the middle of a file
  7  *   new_block:    acquire a new block
  8  */
  9 
 10 #include "fs.h"
 11 #include <string.h>
 12 #include "buf.h"
 13 #include "file.h"
 14 #include "fproc.h"
 15 #include "inode.h"
 16 #include "super.h"
 17 
 18 FORWARD _PROTOTYPE( int write_map, (struct inode *rip, off_t position,
 19                         zone_t new_zone)                                );
 20 
 21 FORWARD _PROTOTYPE( void wr_indir, (struct buf *bp, int index, zone_t zone) );
 22 
 23 /*===========================================================================*
 24  *                              do_write                                     *
 25  *===========================================================================*/
 26 PUBLIC int do_write()
 27 {
 28 /* Perform the write(fd, buffer, nbytes) system call. */
 29 
 30   return(read_write(WRITING));
 31 }
 32 
 33 
 34 /*===========================================================================*
 35  *                              write_map                                    *
 36  *===========================================================================*/
 37 PRIVATE int write_map(rip, position, new_zone)
 38 register struct inode *rip;     /* pointer to inode to be changed */
 39 off_t position;                 /* file address to be mapped */
 40 zone_t new_zone;                /* zone # to be inserted */
 41 {
 42 /* Write a new zone into an inode. */
 43   int scale, ind_ex, new_ind, new_dbl, zones, nr_indirects, single, zindex, ex;
 44   zone_t z, z1;
 45   register block_t b;
 46   long excess, zone;
 47   struct buf *bp;
 48 
 49   rip->i_dirt = DIRTY;          /* inode will be changed */
 50   bp = NIL_BUF;
 51   scale = rip->i_sp->s_log_zone_size;           /* for zone-block conversion */
 52   zone = (position/BLOCK_SIZE) >> scale;        /* relative zone # to insert */
 53   zones = rip->i_ndzones;       /* # direct zones in the inode */
 54   nr_indirects = rip->i_nindirs;/* # indirect zones per indirect block */
 55 
 56   /* Is 'position' to be found in the inode itself? */
 57   if (zone < zones) {
 58         zindex = (int) zone;    /* we need an integer here */
 59         rip->i_zone[zindex] = new_zone;
 60         return(OK);
 61   }
 62 
 63   /* It is not in the inode, so it must be single or double indirect. */
 64   excess = zone - zones;        /* first Vx_NR_DZONES don't count */
 65   new_ind = FALSE;
 66   new_dbl = FALSE;
 67 
 68   if (excess < nr_indirects) {
 69         /* 'position' can be located via the single indirect block. */
 70         z1 = rip->i_zone[zones];        /* single indirect zone */
 71         single = TRUE;
 72   } else {
 73         /* 'position' can be located via the double indirect block. */
 74         if ( (z = rip->i_zone[zones+1]) == NO_ZONE) {
 75                 /* Create the double indirect block. */
 76                 if ( (z = alloc_zone(rip->i_dev, rip->i_zone[0])) == NO_ZONE)
 77                         return(err_code);
 78                 rip->i_zone[zones+1] = z;
 79                 new_dbl = TRUE; /* set flag for later */
 80         }
 81 
 82         /* Either way, 'z' is zone number for double indirect block. */
 83         excess -= nr_indirects; /* single indirect doesn't count */
 84         ind_ex = (int) (excess / nr_indirects);
 85         excess = excess % nr_indirects;
 86         if (ind_ex >= nr_indirects) return(EFBIG);
 87         b = (block_t) z << scale;
 88         bp = get_block(rip->i_dev, b, (new_dbl ? NO_READ : NORMAL));
 89         if (new_dbl) zero_block(bp);
 90         z1 = rd_indir(bp, ind_ex);
 91         single = FALSE;
 92   }
 93 
 94   /* z1 is now single indirect zone; 'excess' is index. */
 95   if (z1 == NO_ZONE) {
 96         /* Create indirect block and store zone # in inode or dbl indir blk. */
 97         z1 = alloc_zone(rip->i_dev, rip->i_zone[0]);
 98         if (single)
 99                 rip->i_zone[zones] = z1;        /* update inode */
100         else
101                 wr_indir(bp, ind_ex, z1);       /* update dbl indir */
102 
103         new_ind = TRUE;
104         if (bp != NIL_BUF) bp->b_dirt = DIRTY;  /* if double ind, it is dirty*/
105         if (z1 == NO_ZONE) {
106                 put_block(bp, INDIRECT_BLOCK);  /* release dbl indirect blk */
107                 return(err_code);       /* couldn't create single ind */
108         }
109   }
110   put_block(bp, INDIRECT_BLOCK);        /* release double indirect blk */
111 
112   /* z1 is indirect block's zone number. */
113   b = (block_t) z1 << scale;
114   bp = get_block(rip->i_dev, b, (new_ind ? NO_READ : NORMAL) );
115   if (new_ind) zero_block(bp);
116   ex = (int) excess;                    /* we need an int here */
117   wr_indir(bp, ex, new_zone);
118   bp->b_dirt = DIRTY;
119   put_block(bp, INDIRECT_BLOCK);
120 
121   return(OK);
122 }
123 
124 
125 /*===========================================================================*
126  *                              wr_indir                                     *
127  *===========================================================================*/
128 PRIVATE void wr_indir(bp, index, zone)
129 struct buf *bp;                 /* pointer to indirect block */
130 int index;                      /* index into *bp */
131 zone_t zone;                    /* zone to write */
132 {
133 /* Given a pointer to an indirect block, write one entry. */
134 
135   struct super_block *sp;
136 
137   sp = get_super(bp->b_dev);    /* need super block to find file sys type */
138 
139   /* write a zone into an indirect block */
140   if (sp->s_version == V1)
141         bp->b_v1_ind[index] = (zone1_t) conv2(sp->s_native, (int)  zone);
142   else
143         bp->b_v2_ind[index] = (zone_t)  conv4(sp->s_native, (long) zone);
144 }
145 
146 
147 /*===========================================================================*
148  *                              clear_zone                                   *
149  *===========================================================================*/
150 PUBLIC void clear_zone(rip, pos, flag)
151 register struct inode *rip;     /* inode to clear */
152 off_t pos;                      /* points to block to clear */
153 int flag;                       /* 0 if called by read_write, 1 by new_block */
154 {
155 /* Zero a zone, possibly starting in the middle.  The parameter 'pos' gives
156  * a byte in the first block to be zeroed.  Clearzone() is called from 
157  * read_write and new_block().
158  */
159 
160   register struct buf *bp;
161   register block_t b, blo, bhi;
162   register off_t next;
163   register int scale;
164   register zone_t zone_size;
165 
166   /* If the block size and zone size are the same, clear_zone() not needed. */
167   scale = rip->i_sp->s_log_zone_size;
168   if (scale == 0) return;
169 
170   zone_size = (zone_t) BLOCK_SIZE << scale;
171   if (flag == 1) pos = (pos/zone_size) * zone_size;
172   next = pos + BLOCK_SIZE - 1;
173 
174   /* If 'pos' is in the last block of a zone, do not clear the zone. */
175   if (next/zone_size != pos/zone_size) return;
176   if ( (blo = read_map(rip, next)) == NO_BLOCK) return;
177   bhi = (  ((blo>>scale)+1) << scale)   - 1;
178 
179   /* Clear all the blocks between 'blo' and 'bhi'. */
180   for (b = blo; b <= bhi; b++) {
181         bp = get_block(rip->i_dev, b, NO_READ);
182         zero_block(bp);
183         put_block(bp, FULL_DATA_BLOCK);
184   }
185 }
186 
187 
188 /*===========================================================================*
189  *                              new_block                                    *
190  *===========================================================================*/
191 PUBLIC struct buf *new_block(rip, position)
192 register struct inode *rip;     /* pointer to inode */
193 off_t position;                 /* file pointer */
194 {
195 /* Acquire a new block and return a pointer to it.  Doing so may require
196  * allocating a complete zone, and then returning the initial block.
197  * On the other hand, the current zone may still have some unused blocks.
198  */
199 
200   register struct buf *bp;
201   block_t b, base_block;
202   zone_t z;
203   zone_t zone_size;
204   int scale, r;
205   struct super_block *sp;
206 
207   /* Is another block available in the current zone? */
208   if ( (b = read_map(rip, position)) == NO_BLOCK) {
209         /* Choose first zone if possible. */
210         /* Lose if the file is nonempty but the first zone number is NO_ZONE
211          * corresponding to a zone full of zeros.  It would be better to
212          * search near the last real zone.
213          */
214         if (rip->i_zone[0] == NO_ZONE) {
215                 sp = rip->i_sp;
216                 z = sp->s_firstdatazone;
217         } else {
218                 z = rip->i_zone[0];     /* hunt near first zone */
219         }
220         if ( (z = alloc_zone(rip->i_dev, z)) == NO_ZONE) return(NIL_BUF);
221         if ( (r = write_map(rip, position, z)) != OK) {
222                 free_zone(rip->i_dev, z);
223                 err_code = r;
224                 return(NIL_BUF);
225         }
226 
227         /* If we are not writing at EOF, clear the zone, just to be safe. */
228         if ( position != rip->i_size) clear_zone(rip, position, 1);
229         scale = rip->i_sp->s_log_zone_size;
230         base_block = (block_t) z << scale;
231         zone_size = (zone_t) BLOCK_SIZE << scale;
232         b = base_block + (block_t)((position % zone_size)/BLOCK_SIZE);
233   }
234 
235   bp = get_block(rip->i_dev, b, NO_READ);
236   zero_block(bp);
237   return(bp);
238 }
239 
240 
241 /*===========================================================================*
242  *                              zero_block                                   *
243  *===========================================================================*/
244 PUBLIC void zero_block(bp)
245 register struct buf *bp;        /* pointer to buffer to zero */
246 {
247 /* Zero a block. */
248 
249   memset(bp->b_data, 0, BLOCK_SIZE);
250   bp->b_dirt = DIRTY;
251 }
252 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.