📄 write.c
字号:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/fs/write.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
24000 /* This file is the counterpart of "read.c". It contains the code for writing
24001 * insofar as this is not contained in read_write().
24002 *
24003 * The entry points into this file are
24004 * do_write: call read_write to perform the WRITE system call
24005 * clear_zone: erase a zone in the middle of a file
24006 * new_block: acquire a new block
24007 */
24008
24009 #include "fs.h"
24010 #include <string.h>
24011 #include "buf.h"
24012 #include "file.h"
24013 #include "fproc.h"
24014 #include "inode.h"
24015 #include "super.h"
24016
24017 FORWARD _PROTOTYPE( int write_map, (struct inode *rip, off_t position,
24018 zone_t new_zone) );
24019
24020 FORWARD _PROTOTYPE( void wr_indir, (struct buf *bp, int index, zone_t zone) );
24021
24022 /*===========================================================================*
24023 * do_write *
24024 *===========================================================================*/
24025 PUBLIC int do_write()
24026 {
24027 /* Perform the write(fd, buffer, nbytes) system call. */
24028
24029 return(read_write(WRITING));
24030 }
24033 /*===========================================================================*
24034 * write_map *
24035 *===========================================================================*/
24036 PRIVATE int write_map(rip, position, new_zone)
24037 register struct inode *rip; /* pointer to inode to be changed */
24038 off_t position; /* file address to be mapped */
24039 zone_t new_zone; /* zone # to be inserted */
24040 {
24041 /* Write a new zone into an inode. */
24042 int scale, ind_ex, new_ind, new_dbl, zones, nr_indirects, single, zindex, ex;
24043 zone_t z, z1;
24044 register block_t b;
24045 long excess, zone;
24046 struct buf *bp;
24047
24048 rip->i_dirt = DIRTY; /* inode will be changed */
24049 bp = NIL_BUF;
24050 scale = rip->i_sp->s_log_zone_size; /* for zone-block conversion */
24051 zone = (position/BLOCK_SIZE) >> scale; /* relative zone # to insert */
24052 zones = rip->i_ndzones; /* # direct zones in the inode */
24053 nr_indirects = rip->i_nindirs;/* # indirect zones per indirect block */
24054
24055 /* Is 'position' to be found in the inode itself? */
24056 if (zone < zones) {
24057 zindex = (int) zone; /* we need an integer here */
24058 rip->i_zone[zindex] = new_zone;
24059 return(OK);
24060 }
24061
24062 /* It is not in the inode, so it must be single or double indirect. */
24063 excess = zone - zones; /* first Vx_NR_DZONES don't count */
24064 new_ind = FALSE;
24065 new_dbl = FALSE;
24066
24067 if (excess < nr_indirects) {
24068 /* 'position' can be located via the single indirect block. */
24069 z1 = rip->i_zone[zones]; /* single indirect zone */
24070 single = TRUE;
24071 } else {
24072 /* 'position' can be located via the double indirect block. */
24073 if ( (z = rip->i_zone[zones+1]) == NO_ZONE) {
24074 /* Create the double indirect block. */
24075 if ( (z = alloc_zone(rip->i_dev, rip->i_zone[0])) == NO_ZONE)
24076 return(err_code);
24077 rip->i_zone[zones+1] = z;
24078 new_dbl = TRUE; /* set flag for later */
24079 }
24080
24081 /* Either way, 'z' is zone number for double indirect block. */
24082 excess -= nr_indirects; /* single indirect doesn't count */
24083 ind_ex = (int) (excess / nr_indirects);
24084 excess = excess % nr_indirects;
24085 if (ind_ex >= nr_indirects) return(EFBIG);
24086 b = (block_t) z << scale;
24087 bp = get_block(rip->i_dev, b, (new_dbl ? NO_READ : NORMAL));
24088 if (new_dbl) zero_block(bp);
24089 z1 = rd_indir(bp, ind_ex);
24090 single = FALSE;
24091 }
24092
24093 /* z1 is now single indirect zone; 'excess' is index. */
24094 if (z1 == NO_ZONE) {
24095 /* Create indirect block and store zone # in inode or dbl indir blk. */
24096 z1 = alloc_zone(rip->i_dev, rip->i_zone[0]);
24097 if (single)
24098 rip->i_zone[zones] = z1; /* update inode */
24099 else
24100 wr_indir(bp, ind_ex, z1); /* update dbl indir */
24101
24102 new_ind = TRUE;
24103 if (bp != NIL_BUF) bp->b_dirt = DIRTY; /* if double ind, it is dirty*/
24104 if (z1 == NO_ZONE) {
24105 put_block(bp, INDIRECT_BLOCK); /* release dbl indirect blk */
24106 return(err_code); /* couldn't create single ind */
24107 }
24108 }
24109 put_block(bp, INDIRECT_BLOCK); /* release double indirect blk */
24110
24111 /* z1 is indirect block's zone number. */
24112 b = (block_t) z1 << scale;
24113 bp = get_block(rip->i_dev, b, (new_ind ? NO_READ : NORMAL) );
24114 if (new_ind) zero_block(bp);
24115 ex = (int) excess; /* we need an int here */
24116 wr_indir(bp, ex, new_zone);
24117 bp->b_dirt = DIRTY;
24118 put_block(bp, INDIRECT_BLOCK);
24119
24120 return(OK);
24121 }
24124 /*===========================================================================*
24125 * wr_indir *
24126 *===========================================================================*/
24127 PRIVATE void wr_indir(bp, index, zone)
24128 struct buf *bp; /* pointer to indirect block */
24129 int index; /* index into *bp */
24130 zone_t zone; /* zone to write */
24131 {
24132 /* Given a pointer to an indirect block, write one entry. */
24133
24134 struct super_block *sp;
24135
24136 sp = get_super(bp->b_dev); /* need super block to find file sys type */
24137
24138 /* write a zone into an indirect block */
24139 if (sp->s_version == V1)
24140 bp->b_v1_ind[index] = (zone1_t) conv2(sp->s_native, (int) zone);
24141 else
24142 bp->b_v2_ind[index] = (zone_t) conv4(sp->s_native, (long) zone);
24143 }
24146 /*===========================================================================*
24147 * clear_zone *
24148 *===========================================================================*/
24149 PUBLIC void clear_zone(rip, pos, flag)
24150 register struct inode *rip; /* inode to clear */
24151 off_t pos; /* points to block to clear */
24152 int flag; /* 0 if called by read_write, 1 by new_block */
24153 {
24154 /* Zero a zone, possibly starting in the middle. The parameter 'pos' gives
24155 * a byte in the first block to be zeroed. Clearzone() is called from
24156 * read_write and new_block().
24157 */
24158
24159 register struct buf *bp;
24160 register block_t b, blo, bhi;
24161 register off_t next;
24162 register int scale;
24163 register zone_t zone_size;
24164
24165 /* If the block size and zone size are the same, clear_zone() not needed. */
24166 scale = rip->i_sp->s_log_zone_size;
24167 if (scale == 0) return;
24168
24169 zone_size = (zone_t) BLOCK_SIZE << scale;
24170 if (flag == 1) pos = (pos/zone_size) * zone_size;
24171 next = pos + BLOCK_SIZE - 1;
24172
24173 /* If 'pos' is in the last block of a zone, do not clear the zone. */
24174 if (next/zone_size != pos/zone_size) return;
24175 if ( (blo = read_map(rip, next)) == NO_BLOCK) return;
24176 bhi = ( ((blo>>scale)+1) << scale) - 1;
24177
24178 /* Clear all the blocks between 'blo' and 'bhi'. */
24179 for (b = blo; b <= bhi; b++) {
24180 bp = get_block(rip->i_dev, b, NO_READ);
24181 zero_block(bp);
24182 put_block(bp, FULL_DATA_BLOCK);
24183 }
24184 }
24187 /*===========================================================================*
24188 * new_block *
24189 *===========================================================================*/
24190 PUBLIC struct buf *new_block(rip, position)
24191 register struct inode *rip; /* pointer to inode */
24192 off_t position; /* file pointer */
24193 {
24194 /* Acquire a new block and return a pointer to it. Doing so may require
24195 * allocating a complete zone, and then returning the initial block.
24196 * On the other hand, the current zone may still have some unused blocks.
24197 */
24198
24199 register struct buf *bp;
24200 block_t b, base_block;
24201 zone_t z;
24202 zone_t zone_size;
24203 int scale, r;
24204 struct super_block *sp;
24205
24206 /* Is another block available in the current zone? */
24207 if ( (b = read_map(rip, position)) == NO_BLOCK) {
24208 /* Choose first zone if possible. */
24209 /* Lose if the file is nonempty but the first zone number is NO_ZONE
24210 * corresponding to a zone full of zeros. It would be better to
24211 * search near the last real zone.
24212 */
24213 if (rip->i_zone[0] == NO_ZONE) {
24214 sp = rip->i_sp;
24215 z = sp->s_firstdatazone;
24216 } else {
24217 z = rip->i_zone[0]; /* hunt near first zone */
24218 }
24219 if ( (z = alloc_zone(rip->i_dev, z)) == NO_ZONE) return(NIL_BUF);
24220 if ( (r = write_map(rip, position, z)) != OK) {
24221 free_zone(rip->i_dev, z);
24222 err_code = r;
24223 return(NIL_BUF);
24224 }
24225
24226 /* If we are not writing at EOF, clear the zone, just to be safe. */
24227 if ( position != rip->i_size) clear_zone(rip, position, 1);
24228 scale = rip->i_sp->s_log_zone_size;
24229 base_block = (block_t) z << scale;
24230 zone_size = (zone_t) BLOCK_SIZE << scale;
24231 b = base_block + (block_t)((position % zone_size)/BLOCK_SIZE);
24232 }
24233
24234 bp = get_block(rip->i_dev, b, NO_READ);
24235 zero_block(bp);
24236 return(bp);
24237 }
24240 /*===========================================================================*
24241 * zero_block *
24242 *===========================================================================*/
24243 PUBLIC void zero_block(bp)
24244 register struct buf *bp; /* pointer to buffer to zero */
24245 {
24246 /* Zero a block. */
24247
24248 memset(bp->b_data, 0, BLOCK_SIZE);
24249 bp->b_dirt = DIRTY;
24250 }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -