xref: /minix3/minix/fs/ext2/write.c (revision 6c46a77d9509a6aefda1522eee2103e194ced4b3)
1433d6423SLionel Sambuc /* This file is the counterpart of "read.c".  It contains the code for writing
2433d6423SLionel Sambuc  * insofar as this is not contained in fs_readwrite().
3433d6423SLionel Sambuc  *
4433d6423SLionel Sambuc  * The entry points into this file are
5433d6423SLionel Sambuc  *   write_map:    write a new block into an inode
6433d6423SLionel Sambuc  *   new_block:    acquire a new block
7433d6423SLionel Sambuc  *   zero_block:   overwrite a block with zeroes
8433d6423SLionel Sambuc  *
9433d6423SLionel Sambuc  * Created (MFS based):
10433d6423SLionel Sambuc  *   February 2010 (Evgeniy Ivanov)
11433d6423SLionel Sambuc  */
12433d6423SLionel Sambuc 
13433d6423SLionel Sambuc #include "fs.h"
14433d6423SLionel Sambuc #include <string.h>
15433d6423SLionel Sambuc #include <assert.h>
16433d6423SLionel Sambuc #include <sys/param.h>
17433d6423SLionel Sambuc #include "buf.h"
18433d6423SLionel Sambuc #include "inode.h"
19433d6423SLionel Sambuc #include "super.h"
20433d6423SLionel Sambuc 
21433d6423SLionel Sambuc static void wr_indir(struct buf *bp, int index, block_t block);
22433d6423SLionel Sambuc static int empty_indir(struct buf *, struct super_block *);
23433d6423SLionel Sambuc 
24433d6423SLionel Sambuc /*===========================================================================*
25433d6423SLionel Sambuc  *				write_map				     *
26433d6423SLionel Sambuc  *===========================================================================*/
write_map(rip,position,new_wblock,op)27433d6423SLionel Sambuc int write_map(rip, position, new_wblock, op)
28433d6423SLionel Sambuc struct inode *rip;		/* pointer to inode to be changed */
29433d6423SLionel Sambuc off_t position;			/* file address to be mapped */
30433d6423SLionel Sambuc block_t new_wblock;		/* block # to be inserted */
31433d6423SLionel Sambuc int op;				/* special actions */
32433d6423SLionel Sambuc {
33433d6423SLionel Sambuc /* Write a new block into an inode.
34433d6423SLionel Sambuc  *
35433d6423SLionel Sambuc  * If op includes WMAP_FREE, free the block corresponding to that position
36433d6423SLionel Sambuc  * in the inode ('new_wblock' is ignored then). Also free the indirect block
37433d6423SLionel Sambuc  * if that was the last entry in the indirect block.
38433d6423SLionel Sambuc  * Also free the double/triple indirect block if that was the last entry in
39433d6423SLionel Sambuc  * the double/triple indirect block.
40433d6423SLionel Sambuc  * It's the only function which should take care about rip->i_blocks counter.
41433d6423SLionel Sambuc  */
42433d6423SLionel Sambuc   int index1 = 0, index2 = 0, index3 = 0; /* indexes in single..triple indirect blocks */
43433d6423SLionel Sambuc   long excess, block_pos;
44433d6423SLionel Sambuc   char new_ind = 0, new_dbl = 0, new_triple = 0;
45433d6423SLionel Sambuc   int single = 0, triple = 0;
46433d6423SLionel Sambuc   block_t old_block = NO_BLOCK, b1 = NO_BLOCK, b2 = NO_BLOCK, b3 = NO_BLOCK;
47433d6423SLionel Sambuc   struct buf *bp = NULL,
48433d6423SLionel Sambuc              *bp_dindir = NULL,
49433d6423SLionel Sambuc              *bp_tindir = NULL;
50433d6423SLionel Sambuc   static char first_time = TRUE;
51433d6423SLionel Sambuc   static long addr_in_block;
52433d6423SLionel Sambuc   static long addr_in_block2;
53433d6423SLionel Sambuc   static long doub_ind_s;
54433d6423SLionel Sambuc   static long triple_ind_s;
55433d6423SLionel Sambuc   static long out_range_s;
56433d6423SLionel Sambuc 
57433d6423SLionel Sambuc   if (first_time) {
58433d6423SLionel Sambuc 	addr_in_block = rip->i_sp->s_block_size / BLOCK_ADDRESS_BYTES;
59433d6423SLionel Sambuc 	addr_in_block2 = addr_in_block * addr_in_block;
60433d6423SLionel Sambuc 	doub_ind_s = EXT2_NDIR_BLOCKS + addr_in_block;
61433d6423SLionel Sambuc 	triple_ind_s = doub_ind_s + addr_in_block2;
62433d6423SLionel Sambuc 	out_range_s = triple_ind_s + addr_in_block2 * addr_in_block;
63433d6423SLionel Sambuc 	first_time = FALSE;
64433d6423SLionel Sambuc   }
65433d6423SLionel Sambuc 
66433d6423SLionel Sambuc   block_pos = position / rip->i_sp->s_block_size; /* relative blk # in file */
67433d6423SLionel Sambuc   rip->i_dirt = IN_DIRTY;		/* inode will be changed */
68433d6423SLionel Sambuc 
69433d6423SLionel Sambuc   /* Is 'position' to be found in the inode itself? */
70433d6423SLionel Sambuc   if (block_pos < EXT2_NDIR_BLOCKS) {
71433d6423SLionel Sambuc 	if (rip->i_block[block_pos] != NO_BLOCK && (op & WMAP_FREE)) {
72433d6423SLionel Sambuc 		free_block(rip->i_sp, rip->i_block[block_pos]);
73433d6423SLionel Sambuc 		rip->i_block[block_pos] = NO_BLOCK;
74433d6423SLionel Sambuc 		rip->i_blocks -= rip->i_sp->s_sectors_in_block;
75433d6423SLionel Sambuc 	} else {
76433d6423SLionel Sambuc 		rip->i_block[block_pos] = new_wblock;
77433d6423SLionel Sambuc 		rip->i_blocks += rip->i_sp->s_sectors_in_block;
78433d6423SLionel Sambuc 	}
79433d6423SLionel Sambuc 	return(OK);
80433d6423SLionel Sambuc   }
81433d6423SLionel Sambuc 
82433d6423SLionel Sambuc   /* It is not in the inode, so it must be single, double or triple indirect */
83433d6423SLionel Sambuc   if (block_pos < doub_ind_s) {
84433d6423SLionel Sambuc       b1 = rip->i_block[EXT2_NDIR_BLOCKS]; /* addr of single indirect block */
85433d6423SLionel Sambuc       index1 = block_pos - EXT2_NDIR_BLOCKS;
86433d6423SLionel Sambuc       single = TRUE;
87433d6423SLionel Sambuc   } else if (block_pos >= out_range_s) { /* TODO: do we need it? */
88433d6423SLionel Sambuc 	return(EFBIG);
89433d6423SLionel Sambuc   } else {
90433d6423SLionel Sambuc 	/* double or triple indirect block. At first if it's triple,
91433d6423SLionel Sambuc 	 * find double indirect block.
92433d6423SLionel Sambuc 	 */
93433d6423SLionel Sambuc 	excess = block_pos - doub_ind_s;
94433d6423SLionel Sambuc 	b2 = rip->i_block[EXT2_DIND_BLOCK];
95433d6423SLionel Sambuc 	if (block_pos >= triple_ind_s) {
96433d6423SLionel Sambuc 		b3 = rip->i_block[EXT2_TIND_BLOCK];
97433d6423SLionel Sambuc 		if (b3 == NO_BLOCK && !(op & WMAP_FREE)) {
98433d6423SLionel Sambuc 		/* Create triple indirect block. */
99433d6423SLionel Sambuc 			if ( (b3 = alloc_block(rip, rip->i_bsearch) ) == NO_BLOCK) {
100433d6423SLionel Sambuc 				ext2_debug("failed to allocate tblock near %d\n", rip->i_block[0]);
101433d6423SLionel Sambuc 				return(ENOSPC);
102433d6423SLionel Sambuc 			}
103433d6423SLionel Sambuc 			rip->i_block[EXT2_TIND_BLOCK] = b3;
104433d6423SLionel Sambuc 			rip->i_blocks += rip->i_sp->s_sectors_in_block;
105433d6423SLionel Sambuc 			new_triple = TRUE;
106433d6423SLionel Sambuc 		}
107433d6423SLionel Sambuc 		/* 'b3' is block number for triple indirect block, either old
108433d6423SLionel Sambuc 		 * or newly created.
109433d6423SLionel Sambuc 		 * If there wasn't one and WMAP_FREE is set, 'b3' is NO_BLOCK.
110433d6423SLionel Sambuc 		 */
111433d6423SLionel Sambuc 		if (b3 == NO_BLOCK && (op & WMAP_FREE)) {
112433d6423SLionel Sambuc 		/* WMAP_FREE and no triple indirect block - then no
113433d6423SLionel Sambuc 		 * double and single indirect blocks either.
114433d6423SLionel Sambuc 		 */
115433d6423SLionel Sambuc 			b1 = b2 = NO_BLOCK;
116433d6423SLionel Sambuc 		} else {
117433d6423SLionel Sambuc 			bp_tindir = get_block(rip->i_dev, b3, (new_triple ? NO_READ : NORMAL));
118433d6423SLionel Sambuc 			if (new_triple) {
119433d6423SLionel Sambuc 				zero_block(bp_tindir);
120433d6423SLionel Sambuc 				lmfs_markdirty(bp_tindir);
121433d6423SLionel Sambuc 			}
122433d6423SLionel Sambuc 			excess = block_pos - triple_ind_s;
123433d6423SLionel Sambuc 			index3 = excess / addr_in_block2;
124433d6423SLionel Sambuc 			b2 = rd_indir(bp_tindir, index3);
125433d6423SLionel Sambuc 			excess = excess % addr_in_block2;
126433d6423SLionel Sambuc 		}
127433d6423SLionel Sambuc 		triple = TRUE;
128433d6423SLionel Sambuc 	}
129433d6423SLionel Sambuc 
130433d6423SLionel Sambuc 	if (b2 == NO_BLOCK && !(op & WMAP_FREE)) {
131433d6423SLionel Sambuc 	/* Create the double indirect block. */
132433d6423SLionel Sambuc 		if ( (b2 = alloc_block(rip, rip->i_bsearch) ) == NO_BLOCK) {
133433d6423SLionel Sambuc 			/* Release triple ind blk. */
1340314acfbSDavid van Moolenbroek 			put_block(bp_tindir);
135433d6423SLionel Sambuc 			ext2_debug("failed to allocate dblock near %d\n", rip->i_block[0]);
136433d6423SLionel Sambuc 			return(ENOSPC);
137433d6423SLionel Sambuc 		}
138433d6423SLionel Sambuc 		if (triple) {
139433d6423SLionel Sambuc 			wr_indir(bp_tindir, index3, b2);  /* update triple indir */
140433d6423SLionel Sambuc 			lmfs_markdirty(bp_tindir);
141433d6423SLionel Sambuc 		} else {
142433d6423SLionel Sambuc 			rip->i_block[EXT2_DIND_BLOCK] = b2;
143433d6423SLionel Sambuc 		}
144433d6423SLionel Sambuc 		rip->i_blocks += rip->i_sp->s_sectors_in_block;
145433d6423SLionel Sambuc 		new_dbl = TRUE; /* set flag for later */
146433d6423SLionel Sambuc 	}
147433d6423SLionel Sambuc 
148433d6423SLionel Sambuc 	/* 'b2' is block number for double indirect block, either old
149433d6423SLionel Sambuc 	 * or newly created.
150433d6423SLionel Sambuc 	 * If there wasn't one and WMAP_FREE is set, 'b2' is NO_BLOCK.
151433d6423SLionel Sambuc 	 */
152433d6423SLionel Sambuc 	if (b2 == NO_BLOCK && (op & WMAP_FREE)) {
153433d6423SLionel Sambuc 	/* WMAP_FREE and no double indirect block - then no
154433d6423SLionel Sambuc 	 * single indirect block either.
155433d6423SLionel Sambuc 	 */
156433d6423SLionel Sambuc 		b1 = NO_BLOCK;
157433d6423SLionel Sambuc 	} else {
158433d6423SLionel Sambuc 		bp_dindir = get_block(rip->i_dev, b2, (new_dbl ? NO_READ : NORMAL));
159433d6423SLionel Sambuc 		if (new_dbl) {
160433d6423SLionel Sambuc 			zero_block(bp_dindir);
161433d6423SLionel Sambuc 			lmfs_markdirty(bp_dindir);
162433d6423SLionel Sambuc 		}
163433d6423SLionel Sambuc 		index2 = excess / addr_in_block;
164433d6423SLionel Sambuc 		b1 = rd_indir(bp_dindir, index2);
165433d6423SLionel Sambuc 		index1 = excess % addr_in_block;
166433d6423SLionel Sambuc 	}
167433d6423SLionel Sambuc 	single = FALSE;
168433d6423SLionel Sambuc   }
169433d6423SLionel Sambuc 
170433d6423SLionel Sambuc   /* b1 is now single indirect block or NO_BLOCK; 'index' is index.
171433d6423SLionel Sambuc    * We have to create the indirect block if it's NO_BLOCK. Unless
172433d6423SLionel Sambuc    * we're freing (WMAP_FREE).
173433d6423SLionel Sambuc    */
174433d6423SLionel Sambuc   if (b1 == NO_BLOCK && !(op & WMAP_FREE)) {
175433d6423SLionel Sambuc 	if ( (b1 = alloc_block(rip, rip->i_bsearch) ) == NO_BLOCK) {
176433d6423SLionel Sambuc 		/* Release dbl and triple indirect blks. */
1770314acfbSDavid van Moolenbroek 		put_block(bp_dindir);
1780314acfbSDavid van Moolenbroek 		put_block(bp_tindir);
179433d6423SLionel Sambuc 		ext2_debug("failed to allocate dblock near %d\n", rip->i_block[0]);
180433d6423SLionel Sambuc 		return(ENOSPC);
181433d6423SLionel Sambuc 	}
182433d6423SLionel Sambuc 	if (single) {
183433d6423SLionel Sambuc 		rip->i_block[EXT2_NDIR_BLOCKS] = b1; /* update inode single indirect */
184433d6423SLionel Sambuc 	} else {
185433d6423SLionel Sambuc 		wr_indir(bp_dindir, index2, b1);  /* update dbl indir */
186433d6423SLionel Sambuc 		lmfs_markdirty(bp_dindir);
187433d6423SLionel Sambuc 	}
188433d6423SLionel Sambuc 	rip->i_blocks += rip->i_sp->s_sectors_in_block;
189433d6423SLionel Sambuc 	new_ind = TRUE;
190433d6423SLionel Sambuc   }
191433d6423SLionel Sambuc 
192433d6423SLionel Sambuc   /* b1 is indirect block's number (unless it's NO_BLOCK when we're
193433d6423SLionel Sambuc    * freeing).
194433d6423SLionel Sambuc    */
195433d6423SLionel Sambuc   if (b1 != NO_BLOCK) {
196433d6423SLionel Sambuc 	bp = get_block(rip->i_dev, b1, (new_ind ? NO_READ : NORMAL) );
197433d6423SLionel Sambuc 	if (new_ind)
198433d6423SLionel Sambuc 		zero_block(bp);
199433d6423SLionel Sambuc 	if (op & WMAP_FREE) {
200433d6423SLionel Sambuc 		if ((old_block = rd_indir(bp, index1)) != NO_BLOCK) {
201433d6423SLionel Sambuc 			free_block(rip->i_sp, old_block);
202433d6423SLionel Sambuc 			rip->i_blocks -= rip->i_sp->s_sectors_in_block;
203433d6423SLionel Sambuc 			wr_indir(bp, index1, NO_BLOCK);
204433d6423SLionel Sambuc 		}
205433d6423SLionel Sambuc 
206433d6423SLionel Sambuc 		/* Last reference in the indirect block gone? Then
207433d6423SLionel Sambuc 		 * free the indirect block.
208433d6423SLionel Sambuc 		 */
209433d6423SLionel Sambuc 		if (empty_indir(bp, rip->i_sp)) {
210433d6423SLionel Sambuc 			free_block(rip->i_sp, b1);
211433d6423SLionel Sambuc 			rip->i_blocks -= rip->i_sp->s_sectors_in_block;
212433d6423SLionel Sambuc 			b1 = NO_BLOCK;
213433d6423SLionel Sambuc 			/* Update the reference to the indirect block to
214433d6423SLionel Sambuc 			 * NO_BLOCK - in the double indirect block if there
215433d6423SLionel Sambuc 			 * is one, otherwise in the inode directly.
216433d6423SLionel Sambuc 			 */
217433d6423SLionel Sambuc 			if (single) {
218433d6423SLionel Sambuc 				rip->i_block[EXT2_NDIR_BLOCKS] = b1;
219433d6423SLionel Sambuc 			} else {
220433d6423SLionel Sambuc 				wr_indir(bp_dindir, index2, b1);
221433d6423SLionel Sambuc 				lmfs_markdirty(bp_dindir);
222433d6423SLionel Sambuc 			}
223433d6423SLionel Sambuc 		}
224433d6423SLionel Sambuc 	} else {
225433d6423SLionel Sambuc 		wr_indir(bp, index1, new_wblock);
226433d6423SLionel Sambuc 		rip->i_blocks += rip->i_sp->s_sectors_in_block;
227433d6423SLionel Sambuc 	}
228433d6423SLionel Sambuc 	/* b1 equals NO_BLOCK only when we are freeing up the indirect block. */
229e94f856bSDavid van Moolenbroek 	if(b1 != NO_BLOCK)
230433d6423SLionel Sambuc 		lmfs_markdirty(bp);
2310314acfbSDavid van Moolenbroek 	put_block(bp);
232433d6423SLionel Sambuc   }
233433d6423SLionel Sambuc 
234433d6423SLionel Sambuc   /* If the single indirect block isn't there (or was just freed),
235433d6423SLionel Sambuc    * see if we have to keep the double indirect block, if any.
236433d6423SLionel Sambuc    */
237433d6423SLionel Sambuc   if (b1 == NO_BLOCK && !single && b2 != NO_BLOCK &&
238433d6423SLionel Sambuc      empty_indir(bp_dindir, rip->i_sp)) {
239433d6423SLionel Sambuc 	free_block(rip->i_sp, b2);
240433d6423SLionel Sambuc 	rip->i_blocks -= rip->i_sp->s_sectors_in_block;
241433d6423SLionel Sambuc 	b2 = NO_BLOCK;
242433d6423SLionel Sambuc 	if (triple) {
243433d6423SLionel Sambuc 		wr_indir(bp_tindir, index3, b2);  /* update triple indir */
244433d6423SLionel Sambuc 		lmfs_markdirty(bp_tindir);
245433d6423SLionel Sambuc 	} else {
246433d6423SLionel Sambuc 		rip->i_block[EXT2_DIND_BLOCK] = b2;
247433d6423SLionel Sambuc 	}
248433d6423SLionel Sambuc   }
249433d6423SLionel Sambuc   /* If the double indirect block isn't there (or was just freed),
250433d6423SLionel Sambuc    * see if we have to keep the triple indirect block, if any.
251433d6423SLionel Sambuc    */
252433d6423SLionel Sambuc   if (b2 == NO_BLOCK && triple && b3 != NO_BLOCK &&
253433d6423SLionel Sambuc      empty_indir(bp_tindir, rip->i_sp)) {
254433d6423SLionel Sambuc 	free_block(rip->i_sp, b3);
255433d6423SLionel Sambuc 	rip->i_blocks -= rip->i_sp->s_sectors_in_block;
256433d6423SLionel Sambuc 	rip->i_block[EXT2_TIND_BLOCK] = NO_BLOCK;
257433d6423SLionel Sambuc   }
258433d6423SLionel Sambuc 
2590314acfbSDavid van Moolenbroek   put_block(bp_dindir);			/* release double indirect blk */
2600314acfbSDavid van Moolenbroek   put_block(bp_tindir);			/* release triple indirect blk */
261433d6423SLionel Sambuc 
262433d6423SLionel Sambuc   return(OK);
263433d6423SLionel Sambuc }
264433d6423SLionel Sambuc 
265433d6423SLionel Sambuc 
266433d6423SLionel Sambuc /*===========================================================================*
267433d6423SLionel Sambuc  *				wr_indir				     *
268433d6423SLionel Sambuc  *===========================================================================*/
wr_indir(bp,wrindex,block)269433d6423SLionel Sambuc static void wr_indir(bp, wrindex, block)
270433d6423SLionel Sambuc struct buf *bp;			/* pointer to indirect block */
271433d6423SLionel Sambuc int wrindex;			/* index into *bp */
272433d6423SLionel Sambuc block_t block;			/* block to write */
273433d6423SLionel Sambuc {
274433d6423SLionel Sambuc /* Given a pointer to an indirect block, write one entry. */
275433d6423SLionel Sambuc 
276433d6423SLionel Sambuc   if(bp == NULL)
277433d6423SLionel Sambuc 	panic("wr_indir() on NULL");
278433d6423SLionel Sambuc 
279433d6423SLionel Sambuc   /* write a block into an indirect block */
280433d6423SLionel Sambuc   b_ind(bp)[wrindex] = conv4(le_CPU, block);
281433d6423SLionel Sambuc }
282433d6423SLionel Sambuc 
283433d6423SLionel Sambuc 
284433d6423SLionel Sambuc /*===========================================================================*
285433d6423SLionel Sambuc  *				empty_indir				     *
286433d6423SLionel Sambuc  *===========================================================================*/
empty_indir(bp,sb)287433d6423SLionel Sambuc static int empty_indir(bp, sb)
288433d6423SLionel Sambuc struct buf *bp;			/* pointer to indirect block */
289433d6423SLionel Sambuc struct super_block *sb;		/* superblock of device block resides on */
290433d6423SLionel Sambuc {
291433d6423SLionel Sambuc /* Return nonzero if the indirect block pointed to by bp contains
292433d6423SLionel Sambuc  * only NO_BLOCK entries.
293433d6423SLionel Sambuc  */
294433d6423SLionel Sambuc   long addr_in_block = sb->s_block_size/4; /* 4 bytes per addr */
295433d6423SLionel Sambuc   int i;
296433d6423SLionel Sambuc   for(i = 0; i < addr_in_block; i++)
297433d6423SLionel Sambuc 	if(b_ind(bp)[i] != NO_BLOCK)
298433d6423SLionel Sambuc 		return(0);
299433d6423SLionel Sambuc   return(1);
300433d6423SLionel Sambuc }
301433d6423SLionel Sambuc 
302433d6423SLionel Sambuc /*===========================================================================*
303433d6423SLionel Sambuc  *				new_block				     *
304433d6423SLionel Sambuc  *===========================================================================*/
new_block(rip,position)305433d6423SLionel Sambuc struct buf *new_block(rip, position)
306433d6423SLionel Sambuc register struct inode *rip;	/* pointer to inode */
307433d6423SLionel Sambuc off_t position;			/* file pointer */
308433d6423SLionel Sambuc {
309433d6423SLionel Sambuc /* Acquire a new block and return a pointer to it. */
310*6c46a77dSDavid van Moolenbroek   struct buf *bp;
311433d6423SLionel Sambuc   int r;
312433d6423SLionel Sambuc   block_t b;
313433d6423SLionel Sambuc 
314433d6423SLionel Sambuc   /* Is another block available? */
315433d6423SLionel Sambuc   if ( (b = read_map(rip, position, 0)) == NO_BLOCK) {
316433d6423SLionel Sambuc 	/* Check if this position follows last allocated
317433d6423SLionel Sambuc 	 * block.
318433d6423SLionel Sambuc 	 */
319433d6423SLionel Sambuc 	block_t goal = NO_BLOCK;
320433d6423SLionel Sambuc 	if (rip->i_last_pos_bl_alloc != 0) {
321433d6423SLionel Sambuc 		off_t position_diff = position - rip->i_last_pos_bl_alloc;
322433d6423SLionel Sambuc 		if (rip->i_bsearch == 0) {
323433d6423SLionel Sambuc 			/* Should never happen, but not critical */
324433d6423SLionel Sambuc 			ext2_debug("warning, i_bsearch is 0, while\
325433d6423SLionel Sambuc 					i_last_pos_bl_alloc is not!");
326433d6423SLionel Sambuc 		}
327433d6423SLionel Sambuc 		if (position_diff <= rip->i_sp->s_block_size) {
328433d6423SLionel Sambuc 			goal = rip->i_bsearch + 1;
329433d6423SLionel Sambuc 		} else {
330433d6423SLionel Sambuc 			/* Non-sequential write operation,
331433d6423SLionel Sambuc 			 * disable preallocation
332433d6423SLionel Sambuc 			 * for this inode.
333433d6423SLionel Sambuc 			 */
334433d6423SLionel Sambuc 			rip->i_preallocation = 0;
335433d6423SLionel Sambuc 			discard_preallocated_blocks(rip);
336433d6423SLionel Sambuc 		}
337433d6423SLionel Sambuc 	}
338433d6423SLionel Sambuc 
339433d6423SLionel Sambuc 	if ( (b = alloc_block(rip, goal) ) == NO_BLOCK) {
340433d6423SLionel Sambuc 		err_code = ENOSPC;
341433d6423SLionel Sambuc 		return(NULL);
342433d6423SLionel Sambuc 	}
343433d6423SLionel Sambuc 	if ( (r = write_map(rip, position, b, 0)) != OK) {
344433d6423SLionel Sambuc 		free_block(rip->i_sp, b);
345433d6423SLionel Sambuc 		err_code = r;
346433d6423SLionel Sambuc 		ext2_debug("write_map failed\n");
347433d6423SLionel Sambuc 		return(NULL);
348433d6423SLionel Sambuc 	}
349433d6423SLionel Sambuc 	rip->i_last_pos_bl_alloc = position;
350433d6423SLionel Sambuc 	if (position == 0) {
351433d6423SLionel Sambuc 		/* rip->i_last_pos_bl_alloc points to the block position,
352433d6423SLionel Sambuc 		 * and zero indicates first usage, thus just increment.
353433d6423SLionel Sambuc 		 */
354433d6423SLionel Sambuc 		rip->i_last_pos_bl_alloc++;
355433d6423SLionel Sambuc 	}
356433d6423SLionel Sambuc   }
357433d6423SLionel Sambuc 
358*6c46a77dSDavid van Moolenbroek   r = lmfs_get_block_ino(&bp, rip->i_dev, b, NO_READ, rip->i_num,
359433d6423SLionel Sambuc 	rounddown(position, rip->i_sp->s_block_size));
360*6c46a77dSDavid van Moolenbroek   if (r != OK)
361*6c46a77dSDavid van Moolenbroek 	panic("ext2: error getting block (%llu,%u): %d", rip->i_dev, b, r);
362433d6423SLionel Sambuc   zero_block(bp);
363433d6423SLionel Sambuc   return(bp);
364433d6423SLionel Sambuc }
365433d6423SLionel Sambuc 
366433d6423SLionel Sambuc /*===========================================================================*
367433d6423SLionel Sambuc  *				zero_block				     *
368433d6423SLionel Sambuc  *===========================================================================*/
zero_block(bp)369433d6423SLionel Sambuc void zero_block(bp)
370433d6423SLionel Sambuc register struct buf *bp;	/* pointer to buffer to zero */
371433d6423SLionel Sambuc {
372433d6423SLionel Sambuc /* Zero a block. */
373433d6423SLionel Sambuc   ASSERT(bp->data);
3740314acfbSDavid van Moolenbroek   memset(b_data(bp), 0, lmfs_fs_block_size());
375433d6423SLionel Sambuc   lmfs_markdirty(bp);
376433d6423SLionel Sambuc }
377