xref: /minix3/sys/fs/v7fs/v7fs_datablock.c (revision 9f988b79349f9b89ecc822458c30ec8897558560)
1*9f988b79SJean-Baptiste Boric /*	$NetBSD: v7fs_datablock.c,v 1.5 2011/08/14 09:02:07 apb Exp $	*/
2*9f988b79SJean-Baptiste Boric 
3*9f988b79SJean-Baptiste Boric /*-
4*9f988b79SJean-Baptiste Boric  * Copyright (c) 2011 The NetBSD Foundation, Inc.
5*9f988b79SJean-Baptiste Boric  * All rights reserved.
6*9f988b79SJean-Baptiste Boric  *
7*9f988b79SJean-Baptiste Boric  * This code is derived from software contributed to The NetBSD Foundation
8*9f988b79SJean-Baptiste Boric  * by UCHIYAMA Yasushi.
9*9f988b79SJean-Baptiste Boric  *
10*9f988b79SJean-Baptiste Boric  * Redistribution and use in source and binary forms, with or without
11*9f988b79SJean-Baptiste Boric  * modification, are permitted provided that the following conditions
12*9f988b79SJean-Baptiste Boric  * are met:
13*9f988b79SJean-Baptiste Boric  * 1. Redistributions of source code must retain the above copyright
14*9f988b79SJean-Baptiste Boric  *    notice, this list of conditions and the following disclaimer.
15*9f988b79SJean-Baptiste Boric  * 2. Redistributions in binary form must reproduce the above copyright
16*9f988b79SJean-Baptiste Boric  *    notice, this list of conditions and the following disclaimer in the
17*9f988b79SJean-Baptiste Boric  *    documentation and/or other materials provided with the distribution.
18*9f988b79SJean-Baptiste Boric  *
19*9f988b79SJean-Baptiste Boric  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20*9f988b79SJean-Baptiste Boric  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21*9f988b79SJean-Baptiste Boric  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22*9f988b79SJean-Baptiste Boric  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23*9f988b79SJean-Baptiste Boric  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24*9f988b79SJean-Baptiste Boric  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25*9f988b79SJean-Baptiste Boric  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26*9f988b79SJean-Baptiste Boric  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27*9f988b79SJean-Baptiste Boric  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28*9f988b79SJean-Baptiste Boric  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29*9f988b79SJean-Baptiste Boric  * POSSIBILITY OF SUCH DAMAGE.
30*9f988b79SJean-Baptiste Boric  */
31*9f988b79SJean-Baptiste Boric 
32*9f988b79SJean-Baptiste Boric #if HAVE_NBTOOL_CONFIG_H
33*9f988b79SJean-Baptiste Boric #include "nbtool_config.h"
34*9f988b79SJean-Baptiste Boric #endif
35*9f988b79SJean-Baptiste Boric 
36*9f988b79SJean-Baptiste Boric #include <sys/cdefs.h>
37*9f988b79SJean-Baptiste Boric __KERNEL_RCSID(0, "$NetBSD: v7fs_datablock.c,v 1.5 2011/08/14 09:02:07 apb Exp $");
38*9f988b79SJean-Baptiste Boric #if defined _KERNEL_OPT
39*9f988b79SJean-Baptiste Boric #include "opt_v7fs.h"
40*9f988b79SJean-Baptiste Boric #endif
41*9f988b79SJean-Baptiste Boric 
42*9f988b79SJean-Baptiste Boric #include <sys/types.h>
43*9f988b79SJean-Baptiste Boric #ifdef _KERNEL
44*9f988b79SJean-Baptiste Boric #include <sys/systm.h>
45*9f988b79SJean-Baptiste Boric #include <sys/param.h>
46*9f988b79SJean-Baptiste Boric #else
47*9f988b79SJean-Baptiste Boric #include <stdio.h>
48*9f988b79SJean-Baptiste Boric #include <string.h>
49*9f988b79SJean-Baptiste Boric #include <errno.h>
50*9f988b79SJean-Baptiste Boric #endif
51*9f988b79SJean-Baptiste Boric 
52*9f988b79SJean-Baptiste Boric #include "v7fs.h"
53*9f988b79SJean-Baptiste Boric #include "v7fs_impl.h"
54*9f988b79SJean-Baptiste Boric #include "v7fs_endian.h"
55*9f988b79SJean-Baptiste Boric #include "v7fs_inode.h"
56*9f988b79SJean-Baptiste Boric #include "v7fs_datablock.h"
57*9f988b79SJean-Baptiste Boric #include "v7fs_superblock.h"
58*9f988b79SJean-Baptiste Boric 
59*9f988b79SJean-Baptiste Boric #ifdef V7FS_DATABLOCK_DEBUG
60*9f988b79SJean-Baptiste Boric #define	DPRINTF(fmt, args...)	printf("%s: " fmt, __func__, ##args)
61*9f988b79SJean-Baptiste Boric #else
62*9f988b79SJean-Baptiste Boric #define	DPRINTF(fmt, args...)	((void)0)
63*9f988b79SJean-Baptiste Boric #endif
64*9f988b79SJean-Baptiste Boric 
65*9f988b79SJean-Baptiste Boric static int v7fs_datablock_deallocate(struct v7fs_self *, v7fs_daddr_t);
66*9f988b79SJean-Baptiste Boric static int v7fs_loop1(struct v7fs_self *, v7fs_daddr_t, size_t *,
67*9f988b79SJean-Baptiste Boric     int (*)(struct v7fs_self *, void *, v7fs_daddr_t, size_t), void *);
68*9f988b79SJean-Baptiste Boric static int v7fs_loop2(struct v7fs_self *, v7fs_daddr_t, size_t *,
69*9f988b79SJean-Baptiste Boric     int (*)(struct v7fs_self *, void *, v7fs_daddr_t, size_t), void *);
70*9f988b79SJean-Baptiste Boric static v7fs_daddr_t v7fs_link(struct v7fs_self *, v7fs_daddr_t, int);
71*9f988b79SJean-Baptiste Boric static v7fs_daddr_t v7fs_add_leaf(struct v7fs_self *, v7fs_daddr_t, int);
72*9f988b79SJean-Baptiste Boric static v7fs_daddr_t v7fs_unlink(struct v7fs_self *, v7fs_daddr_t, int);
73*9f988b79SJean-Baptiste Boric static v7fs_daddr_t v7fs_remove_leaf(struct v7fs_self *, v7fs_daddr_t, int);
74*9f988b79SJean-Baptiste Boric static v7fs_daddr_t v7fs_remove_self(struct v7fs_self *, v7fs_daddr_t);
75*9f988b79SJean-Baptiste Boric 
76*9f988b79SJean-Baptiste Boric #ifdef V7FS_DATABLOCK_DEBUG
77*9f988b79SJean-Baptiste Boric void daddr_map_dump(const struct v7fs_daddr_map *);
78*9f988b79SJean-Baptiste Boric #else
79*9f988b79SJean-Baptiste Boric #define	daddr_map_dump(x)	((void)0)
80*9f988b79SJean-Baptiste Boric #endif
81*9f988b79SJean-Baptiste Boric 
82*9f988b79SJean-Baptiste Boric bool
datablock_number_sanity(const struct v7fs_self * fs,v7fs_daddr_t blk)83*9f988b79SJean-Baptiste Boric datablock_number_sanity(const struct v7fs_self *fs, v7fs_daddr_t blk)
84*9f988b79SJean-Baptiste Boric {
85*9f988b79SJean-Baptiste Boric 	const struct v7fs_superblock *sb = &fs->superblock;
86*9f988b79SJean-Baptiste Boric 	bool ok = (blk >= sb->datablock_start_sector) &&
87*9f988b79SJean-Baptiste Boric 	    (blk < sb->volume_size);
88*9f988b79SJean-Baptiste Boric 
89*9f988b79SJean-Baptiste Boric #ifdef V7FS_DATABLOCK_DEBUG
90*9f988b79SJean-Baptiste Boric 	if (!ok) {
91*9f988b79SJean-Baptiste Boric 		DPRINTF("Bad data block #%d\n", blk);
92*9f988b79SJean-Baptiste Boric 	}
93*9f988b79SJean-Baptiste Boric #endif
94*9f988b79SJean-Baptiste Boric 
95*9f988b79SJean-Baptiste Boric 	return ok;
96*9f988b79SJean-Baptiste Boric }
97*9f988b79SJean-Baptiste Boric 
98*9f988b79SJean-Baptiste Boric int
v7fs_datablock_allocate(struct v7fs_self * fs,v7fs_daddr_t * block_number)99*9f988b79SJean-Baptiste Boric v7fs_datablock_allocate(struct v7fs_self *fs, v7fs_daddr_t *block_number)
100*9f988b79SJean-Baptiste Boric {
101*9f988b79SJean-Baptiste Boric 	struct v7fs_superblock *sb = &fs->superblock;
102*9f988b79SJean-Baptiste Boric 	v7fs_daddr_t blk;
103*9f988b79SJean-Baptiste Boric 	int error = 0;
104*9f988b79SJean-Baptiste Boric 
105*9f988b79SJean-Baptiste Boric 	*block_number = 0;
106*9f988b79SJean-Baptiste Boric 	SUPERB_LOCK(fs);
107*9f988b79SJean-Baptiste Boric 	do {
108*9f988b79SJean-Baptiste Boric 		if (!sb->total_freeblock) {
109*9f988b79SJean-Baptiste Boric 			DPRINTF("free block exhausted!!!\n");
110*9f988b79SJean-Baptiste Boric 			SUPERB_UNLOCK(fs);
111*9f988b79SJean-Baptiste Boric 			return ENOSPC;
112*9f988b79SJean-Baptiste Boric 		}
113*9f988b79SJean-Baptiste Boric 
114*9f988b79SJean-Baptiste Boric 		/* Get free block from superblock cache. */
115*9f988b79SJean-Baptiste Boric 		blk = sb->freeblock[--sb->nfreeblock];
116*9f988b79SJean-Baptiste Boric 		sb->total_freeblock--;
117*9f988b79SJean-Baptiste Boric 		sb->modified = 1;
118*9f988b79SJean-Baptiste Boric 
119*9f988b79SJean-Baptiste Boric 		/* If nfreeblock is zero, it block is next freeblock link. */
120*9f988b79SJean-Baptiste Boric 		if (sb->nfreeblock == 0) {
121*9f988b79SJean-Baptiste Boric 			if ((error = v7fs_freeblock_update(fs, blk))) {
122*9f988b79SJean-Baptiste Boric 				DPRINTF("no freeblock!!!\n");
123*9f988b79SJean-Baptiste Boric 				SUPERB_UNLOCK(fs);
124*9f988b79SJean-Baptiste Boric 				return error;
125*9f988b79SJean-Baptiste Boric 			}
126*9f988b79SJean-Baptiste Boric 			/* This freeblock link is no longer required. */
127*9f988b79SJean-Baptiste Boric 			/* use as data block. */
128*9f988b79SJean-Baptiste Boric 		}
129*9f988b79SJean-Baptiste Boric 	} while (!datablock_number_sanity(fs, blk)); /* skip bogus block. */
130*9f988b79SJean-Baptiste Boric 	SUPERB_UNLOCK(fs);
131*9f988b79SJean-Baptiste Boric 
132*9f988b79SJean-Baptiste Boric 	DPRINTF("Get freeblock %d\n", blk);
133*9f988b79SJean-Baptiste Boric 	/* Zero clear datablock. */
134*9f988b79SJean-Baptiste Boric 	void *buf;
135*9f988b79SJean-Baptiste Boric 	if (!(buf = scratch_read(fs, blk)))
136*9f988b79SJean-Baptiste Boric 		return EIO;
137*9f988b79SJean-Baptiste Boric 	memset(buf, 0, V7FS_BSIZE);
138*9f988b79SJean-Baptiste Boric 	if (!fs->io.write(fs->io.cookie, buf, blk))
139*9f988b79SJean-Baptiste Boric 		error = EIO;
140*9f988b79SJean-Baptiste Boric 	scratch_free(fs, buf);
141*9f988b79SJean-Baptiste Boric 
142*9f988b79SJean-Baptiste Boric 	if (error == 0)
143*9f988b79SJean-Baptiste Boric 		*block_number = blk;
144*9f988b79SJean-Baptiste Boric 
145*9f988b79SJean-Baptiste Boric 	return error;
146*9f988b79SJean-Baptiste Boric }
147*9f988b79SJean-Baptiste Boric 
148*9f988b79SJean-Baptiste Boric static int
v7fs_datablock_deallocate(struct v7fs_self * fs,v7fs_daddr_t blk)149*9f988b79SJean-Baptiste Boric v7fs_datablock_deallocate(struct v7fs_self *fs, v7fs_daddr_t blk)
150*9f988b79SJean-Baptiste Boric {
151*9f988b79SJean-Baptiste Boric 	struct v7fs_superblock *sb = &fs->superblock;
152*9f988b79SJean-Baptiste Boric 	void *buf;
153*9f988b79SJean-Baptiste Boric 	int error = 0;
154*9f988b79SJean-Baptiste Boric 
155*9f988b79SJean-Baptiste Boric 	if (!datablock_number_sanity(fs, blk))
156*9f988b79SJean-Baptiste Boric 		return EIO;
157*9f988b79SJean-Baptiste Boric 
158*9f988b79SJean-Baptiste Boric 	/* Add to in-core freelist. */
159*9f988b79SJean-Baptiste Boric 	SUPERB_LOCK(fs);
160*9f988b79SJean-Baptiste Boric 	if (sb->nfreeblock < V7FS_MAX_FREEBLOCK) {
161*9f988b79SJean-Baptiste Boric 		sb->freeblock[sb->nfreeblock++] = blk;
162*9f988b79SJean-Baptiste Boric 		sb->total_freeblock++;
163*9f988b79SJean-Baptiste Boric 		sb->modified = 1;
164*9f988b79SJean-Baptiste Boric 		DPRINTF("n_freeblock=%d\n", sb->total_freeblock);
165*9f988b79SJean-Baptiste Boric 		SUPERB_UNLOCK(fs);
166*9f988b79SJean-Baptiste Boric 		return 0;
167*9f988b79SJean-Baptiste Boric 	}
168*9f988b79SJean-Baptiste Boric 
169*9f988b79SJean-Baptiste Boric 	/* No space to push. */
170*9f988b79SJean-Baptiste Boric 	/* Make this block to freeblock list.and current cache moved to this. */
171*9f988b79SJean-Baptiste Boric 	if (!(buf = scratch_read(fs, blk))) {
172*9f988b79SJean-Baptiste Boric 		SUPERB_UNLOCK(fs);
173*9f988b79SJean-Baptiste Boric 		return EIO;	/* Fatal */
174*9f988b79SJean-Baptiste Boric 	}
175*9f988b79SJean-Baptiste Boric 
176*9f988b79SJean-Baptiste Boric 	struct v7fs_freeblock *fb = (struct v7fs_freeblock *)buf;
177*9f988b79SJean-Baptiste Boric 	fb->nfreeblock = V7FS_MAX_FREEBLOCK;
178*9f988b79SJean-Baptiste Boric 	int i;
179*9f988b79SJean-Baptiste Boric 	for (i = 0; i < V7FS_MAX_FREEBLOCK; i++)
180*9f988b79SJean-Baptiste Boric 		fb->freeblock[i] = V7FS_VAL32(fs, sb->freeblock[i]);
181*9f988b79SJean-Baptiste Boric 
182*9f988b79SJean-Baptiste Boric 	if (!fs->io.write(fs->io.cookie, (uint8_t *)fb, blk)) {
183*9f988b79SJean-Baptiste Boric 		error =  EIO;	/* Fatal */
184*9f988b79SJean-Baptiste Boric 	} else {
185*9f988b79SJean-Baptiste Boric 		/* Link. on next allocate, this block is used as datablock, */
186*9f988b79SJean-Baptiste Boric 		/* and swap outed freeblock list is restored. */
187*9f988b79SJean-Baptiste Boric 		sb->freeblock[0] = blk;
188*9f988b79SJean-Baptiste Boric 		sb->nfreeblock = 1;
189*9f988b79SJean-Baptiste Boric 		sb->total_freeblock++;
190*9f988b79SJean-Baptiste Boric 		sb->modified = 1;
191*9f988b79SJean-Baptiste Boric 		DPRINTF("n_freeblock=%d\n", sb->total_freeblock);
192*9f988b79SJean-Baptiste Boric 	}
193*9f988b79SJean-Baptiste Boric 	SUPERB_UNLOCK(fs);
194*9f988b79SJean-Baptiste Boric 	scratch_free(fs, buf);
195*9f988b79SJean-Baptiste Boric 
196*9f988b79SJean-Baptiste Boric 	return error;
197*9f988b79SJean-Baptiste Boric }
198*9f988b79SJean-Baptiste Boric 
199*9f988b79SJean-Baptiste Boric int
v7fs_datablock_addr(size_t sz,struct v7fs_daddr_map * map)200*9f988b79SJean-Baptiste Boric v7fs_datablock_addr(size_t sz, struct v7fs_daddr_map *map)
201*9f988b79SJean-Baptiste Boric {
202*9f988b79SJean-Baptiste Boric #define	NIDX		V7FS_DADDR_PER_BLOCK
203*9f988b79SJean-Baptiste Boric #define	DIRECT_SZ	(V7FS_NADDR_DIRECT * V7FS_BSIZE)
204*9f988b79SJean-Baptiste Boric #define	IDX1_SZ		(NIDX * V7FS_BSIZE)
205*9f988b79SJean-Baptiste Boric #define	IDX2_SZ		(NIDX * NIDX * V7FS_BSIZE)
206*9f988b79SJean-Baptiste Boric #define	ROUND(x, a)	((((x) + ((a) - 1)) & ~((a) - 1)))
207*9f988b79SJean-Baptiste Boric 	if (!sz) {
208*9f988b79SJean-Baptiste Boric 		map->level = 0;
209*9f988b79SJean-Baptiste Boric 		map->index[0] = 0;
210*9f988b79SJean-Baptiste Boric 		return 0;
211*9f988b79SJean-Baptiste Boric 	}
212*9f988b79SJean-Baptiste Boric 
213*9f988b79SJean-Baptiste Boric 	sz = V7FS_ROUND_BSIZE(sz);
214*9f988b79SJean-Baptiste Boric 
215*9f988b79SJean-Baptiste Boric 	/* Direct */
216*9f988b79SJean-Baptiste Boric 	if (sz <= DIRECT_SZ) {
217*9f988b79SJean-Baptiste Boric 		map->level = 0;
218*9f988b79SJean-Baptiste Boric 		map->index[0] = (sz >> V7FS_BSHIFT) - 1;
219*9f988b79SJean-Baptiste Boric 		return 0;
220*9f988b79SJean-Baptiste Boric 	}
221*9f988b79SJean-Baptiste Boric 	/* Index 1 */
222*9f988b79SJean-Baptiste Boric 	sz -= DIRECT_SZ;
223*9f988b79SJean-Baptiste Boric 
224*9f988b79SJean-Baptiste Boric 	if (sz <= IDX1_SZ) {
225*9f988b79SJean-Baptiste Boric 		map->level = 1;
226*9f988b79SJean-Baptiste Boric 		map->index[0] = (sz >> V7FS_BSHIFT) - 1;
227*9f988b79SJean-Baptiste Boric 		return 0;
228*9f988b79SJean-Baptiste Boric 	}
229*9f988b79SJean-Baptiste Boric 	sz -= IDX1_SZ;
230*9f988b79SJean-Baptiste Boric 
231*9f988b79SJean-Baptiste Boric 	/* Index 2 */
232*9f988b79SJean-Baptiste Boric 	if (sz <= IDX2_SZ) {
233*9f988b79SJean-Baptiste Boric 		map->level = 2;
234*9f988b79SJean-Baptiste Boric 		map->index[0] = ROUND(sz, IDX1_SZ) / IDX1_SZ - 1;
235*9f988b79SJean-Baptiste Boric 		map->index[1] = ((sz - (map->index[0] * IDX1_SZ)) >>
236*9f988b79SJean-Baptiste Boric 		    V7FS_BSHIFT) - 1;
237*9f988b79SJean-Baptiste Boric 		return 0;
238*9f988b79SJean-Baptiste Boric 	}
239*9f988b79SJean-Baptiste Boric 	sz -= IDX2_SZ;
240*9f988b79SJean-Baptiste Boric 
241*9f988b79SJean-Baptiste Boric 	/* Index 3 */
242*9f988b79SJean-Baptiste Boric 	map->level = 3;
243*9f988b79SJean-Baptiste Boric 	map->index[0] = ROUND(sz, IDX2_SZ) / IDX2_SZ - 1;
244*9f988b79SJean-Baptiste Boric 	sz -= map->index[0] * IDX2_SZ;
245*9f988b79SJean-Baptiste Boric 	map->index[1] = ROUND(sz, IDX1_SZ) / IDX1_SZ - 1;
246*9f988b79SJean-Baptiste Boric 	sz -= map->index[1] * IDX1_SZ;
247*9f988b79SJean-Baptiste Boric 	map->index[2] = (sz >> V7FS_BSHIFT) - 1;
248*9f988b79SJean-Baptiste Boric 
249*9f988b79SJean-Baptiste Boric 	return map->index[2] >= NIDX ? ENOSPC : 0;
250*9f988b79SJean-Baptiste Boric }
251*9f988b79SJean-Baptiste Boric 
252*9f988b79SJean-Baptiste Boric int
v7fs_datablock_foreach(struct v7fs_self * fs,struct v7fs_inode * p,int (* func)(struct v7fs_self *,void *,v7fs_daddr_t,size_t),void * ctx)253*9f988b79SJean-Baptiste Boric v7fs_datablock_foreach(struct v7fs_self *fs, struct v7fs_inode *p,
254*9f988b79SJean-Baptiste Boric     int (*func)(struct v7fs_self *, void *, v7fs_daddr_t, size_t), void *ctx)
255*9f988b79SJean-Baptiste Boric {
256*9f988b79SJean-Baptiste Boric 	size_t i;
257*9f988b79SJean-Baptiste Boric 	v7fs_daddr_t blk, blk2;
258*9f988b79SJean-Baptiste Boric 	size_t filesize;
259*9f988b79SJean-Baptiste Boric 	bool last;
260*9f988b79SJean-Baptiste Boric 	int ret;
261*9f988b79SJean-Baptiste Boric 
262*9f988b79SJean-Baptiste Boric 	if (!(filesize = v7fs_inode_filesize(p)))
263*9f988b79SJean-Baptiste Boric 		return V7FS_ITERATOR_END;
264*9f988b79SJean-Baptiste Boric #ifdef V7FS_DATABLOCK_DEBUG
265*9f988b79SJean-Baptiste Boric 	size_t sz = filesize;
266*9f988b79SJean-Baptiste Boric #endif
267*9f988b79SJean-Baptiste Boric 
268*9f988b79SJean-Baptiste Boric 	/* Direct */
269*9f988b79SJean-Baptiste Boric 	for (i = 0; i < V7FS_NADDR_DIRECT; i++, filesize -= V7FS_BSIZE) {
270*9f988b79SJean-Baptiste Boric 		blk = p->addr[i];
271*9f988b79SJean-Baptiste Boric 		if (!datablock_number_sanity(fs, blk)) {
272*9f988b79SJean-Baptiste Boric 			DPRINTF("inode#%d direct=%zu filesize=%zu\n",
273*9f988b79SJean-Baptiste Boric 			    p->inode_number, i, sz);
274*9f988b79SJean-Baptiste Boric 			return EIO;
275*9f988b79SJean-Baptiste Boric 		}
276*9f988b79SJean-Baptiste Boric 
277*9f988b79SJean-Baptiste Boric 		last = filesize <= V7FS_BSIZE;
278*9f988b79SJean-Baptiste Boric 		if ((ret = func(fs, ctx, blk, last ? filesize : V7FS_BSIZE)))
279*9f988b79SJean-Baptiste Boric 			return ret;
280*9f988b79SJean-Baptiste Boric 		if (last)
281*9f988b79SJean-Baptiste Boric 			return V7FS_ITERATOR_END;
282*9f988b79SJean-Baptiste Boric 	}
283*9f988b79SJean-Baptiste Boric 
284*9f988b79SJean-Baptiste Boric 	/* Index 1 */
285*9f988b79SJean-Baptiste Boric 	blk = p->addr[V7FS_NADDR_INDEX1];
286*9f988b79SJean-Baptiste Boric 	if (!datablock_number_sanity(fs, blk))
287*9f988b79SJean-Baptiste Boric 		return EIO;
288*9f988b79SJean-Baptiste Boric 
289*9f988b79SJean-Baptiste Boric 	if ((ret = v7fs_loop1(fs, blk, &filesize, func, ctx)))
290*9f988b79SJean-Baptiste Boric 		return ret;
291*9f988b79SJean-Baptiste Boric 
292*9f988b79SJean-Baptiste Boric 	/* Index 2 */
293*9f988b79SJean-Baptiste Boric 	blk = p->addr[V7FS_NADDR_INDEX2];
294*9f988b79SJean-Baptiste Boric 	if (!datablock_number_sanity(fs, blk))
295*9f988b79SJean-Baptiste Boric 		return EIO;
296*9f988b79SJean-Baptiste Boric 
297*9f988b79SJean-Baptiste Boric 	if ((ret = v7fs_loop2(fs, blk, &filesize, func, ctx)))
298*9f988b79SJean-Baptiste Boric 		return ret;
299*9f988b79SJean-Baptiste Boric 
300*9f988b79SJean-Baptiste Boric 	/* Index 3 */
301*9f988b79SJean-Baptiste Boric 	blk = p->addr[V7FS_NADDR_INDEX3];
302*9f988b79SJean-Baptiste Boric 	if (!datablock_number_sanity(fs, blk))
303*9f988b79SJean-Baptiste Boric 		return EIO;
304*9f988b79SJean-Baptiste Boric 
305*9f988b79SJean-Baptiste Boric 	for (i = 0; i < V7FS_DADDR_PER_BLOCK; i++) {
306*9f988b79SJean-Baptiste Boric 		blk2 = v7fs_link(fs, blk, i);
307*9f988b79SJean-Baptiste Boric 		if (!datablock_number_sanity(fs, blk))
308*9f988b79SJean-Baptiste Boric 			return EIO;
309*9f988b79SJean-Baptiste Boric 
310*9f988b79SJean-Baptiste Boric 		if ((ret = v7fs_loop2(fs, blk2, &filesize, func, ctx)))
311*9f988b79SJean-Baptiste Boric 			return ret;
312*9f988b79SJean-Baptiste Boric 	}
313*9f988b79SJean-Baptiste Boric 
314*9f988b79SJean-Baptiste Boric 	return EFBIG;
315*9f988b79SJean-Baptiste Boric }
316*9f988b79SJean-Baptiste Boric 
317*9f988b79SJean-Baptiste Boric static int
v7fs_loop2(struct v7fs_self * fs,v7fs_daddr_t listblk,size_t * filesize,int (* func)(struct v7fs_self *,void *,v7fs_daddr_t,size_t),void * ctx)318*9f988b79SJean-Baptiste Boric v7fs_loop2(struct v7fs_self *fs, v7fs_daddr_t listblk, size_t *filesize,
319*9f988b79SJean-Baptiste Boric     int (*func)(struct v7fs_self *, void *, v7fs_daddr_t, size_t), void *ctx)
320*9f988b79SJean-Baptiste Boric {
321*9f988b79SJean-Baptiste Boric 	v7fs_daddr_t blk;
322*9f988b79SJean-Baptiste Boric 	int ret;
323*9f988b79SJean-Baptiste Boric 	size_t j;
324*9f988b79SJean-Baptiste Boric 
325*9f988b79SJean-Baptiste Boric 	for (j = 0; j < V7FS_DADDR_PER_BLOCK; j++) {
326*9f988b79SJean-Baptiste Boric 		blk = v7fs_link(fs, listblk, j);
327*9f988b79SJean-Baptiste Boric 		if (!datablock_number_sanity(fs, blk))
328*9f988b79SJean-Baptiste Boric 			return EIO;
329*9f988b79SJean-Baptiste Boric 		if ((ret = v7fs_loop1(fs, blk, filesize, func, ctx)))
330*9f988b79SJean-Baptiste Boric 			return ret;
331*9f988b79SJean-Baptiste Boric 	}
332*9f988b79SJean-Baptiste Boric 
333*9f988b79SJean-Baptiste Boric 	return 0;
334*9f988b79SJean-Baptiste Boric }
335*9f988b79SJean-Baptiste Boric 
336*9f988b79SJean-Baptiste Boric static int
v7fs_loop1(struct v7fs_self * fs,v7fs_daddr_t listblk,size_t * filesize,int (* func)(struct v7fs_self *,void *,v7fs_daddr_t,size_t),void * ctx)337*9f988b79SJean-Baptiste Boric v7fs_loop1(struct v7fs_self *fs, v7fs_daddr_t listblk, size_t *filesize,
338*9f988b79SJean-Baptiste Boric     int (*func)(struct v7fs_self *, void *, v7fs_daddr_t, size_t), void *ctx)
339*9f988b79SJean-Baptiste Boric {
340*9f988b79SJean-Baptiste Boric 	v7fs_daddr_t blk;
341*9f988b79SJean-Baptiste Boric 	bool last;
342*9f988b79SJean-Baptiste Boric 	int ret;
343*9f988b79SJean-Baptiste Boric 	size_t k;
344*9f988b79SJean-Baptiste Boric 
345*9f988b79SJean-Baptiste Boric 	for (k = 0; k < V7FS_DADDR_PER_BLOCK; k++, *filesize -= V7FS_BSIZE) {
346*9f988b79SJean-Baptiste Boric 		blk = v7fs_link(fs, listblk, k);
347*9f988b79SJean-Baptiste Boric 		if (!datablock_number_sanity(fs, blk))
348*9f988b79SJean-Baptiste Boric 			return EIO;
349*9f988b79SJean-Baptiste Boric 		last = *filesize <= V7FS_BSIZE;
350*9f988b79SJean-Baptiste Boric 		if ((ret = func(fs, ctx, blk, last ? *filesize : V7FS_BSIZE)))
351*9f988b79SJean-Baptiste Boric 			return ret;
352*9f988b79SJean-Baptiste Boric 		if (last)
353*9f988b79SJean-Baptiste Boric 			return V7FS_ITERATOR_END;
354*9f988b79SJean-Baptiste Boric 	}
355*9f988b79SJean-Baptiste Boric 
356*9f988b79SJean-Baptiste Boric 	return 0;
357*9f988b79SJean-Baptiste Boric }
358*9f988b79SJean-Baptiste Boric 
359*9f988b79SJean-Baptiste Boric v7fs_daddr_t
v7fs_datablock_last(struct v7fs_self * fs,struct v7fs_inode * inode,v7fs_off_t ofs)360*9f988b79SJean-Baptiste Boric v7fs_datablock_last(struct v7fs_self *fs, struct v7fs_inode *inode,
361*9f988b79SJean-Baptiste Boric     v7fs_off_t ofs)
362*9f988b79SJean-Baptiste Boric {
363*9f988b79SJean-Baptiste Boric 	struct v7fs_daddr_map map;
364*9f988b79SJean-Baptiste Boric 	v7fs_daddr_t blk = 0;
365*9f988b79SJean-Baptiste Boric 	v7fs_daddr_t *addr = inode->addr;
366*9f988b79SJean-Baptiste Boric 
367*9f988b79SJean-Baptiste Boric 	/* Inquire last data block location. */
368*9f988b79SJean-Baptiste Boric 	if (v7fs_datablock_addr(ofs, &map) != 0)
369*9f988b79SJean-Baptiste Boric 		return 0;
370*9f988b79SJean-Baptiste Boric 
371*9f988b79SJean-Baptiste Boric 	switch (map.level)
372*9f988b79SJean-Baptiste Boric 	{
373*9f988b79SJean-Baptiste Boric 	case 0: /*Direct */
374*9f988b79SJean-Baptiste Boric 		blk = inode->addr[map.index[0]];
375*9f988b79SJean-Baptiste Boric 		break;
376*9f988b79SJean-Baptiste Boric 	case 1: /*Index1 */
377*9f988b79SJean-Baptiste Boric 		blk = v7fs_link(fs, addr[V7FS_NADDR_INDEX1], map.index[0]);
378*9f988b79SJean-Baptiste Boric 		break;
379*9f988b79SJean-Baptiste Boric 	case 2: /*Index2 */
380*9f988b79SJean-Baptiste Boric 		blk = v7fs_link(fs, v7fs_link(fs,
381*9f988b79SJean-Baptiste Boric 		    addr[V7FS_NADDR_INDEX2], map.index[0]), map.index[1]);
382*9f988b79SJean-Baptiste Boric 		break;
383*9f988b79SJean-Baptiste Boric 	case 3: /*Index3 */
384*9f988b79SJean-Baptiste Boric 		blk = v7fs_link(fs, v7fs_link(fs, v7fs_link(fs,
385*9f988b79SJean-Baptiste Boric 		    addr[V7FS_NADDR_INDEX3], map.index[0]), map.index[1]),
386*9f988b79SJean-Baptiste Boric 		    map.index[2]);
387*9f988b79SJean-Baptiste Boric 		break;
388*9f988b79SJean-Baptiste Boric 	}
389*9f988b79SJean-Baptiste Boric 
390*9f988b79SJean-Baptiste Boric 	return blk;
391*9f988b79SJean-Baptiste Boric }
392*9f988b79SJean-Baptiste Boric 
393*9f988b79SJean-Baptiste Boric int
v7fs_datablock_expand(struct v7fs_self * fs,struct v7fs_inode * inode,size_t sz)394*9f988b79SJean-Baptiste Boric v7fs_datablock_expand(struct v7fs_self *fs, struct v7fs_inode *inode, size_t sz)
395*9f988b79SJean-Baptiste Boric {
396*9f988b79SJean-Baptiste Boric 	size_t old_filesize = inode->filesize;
397*9f988b79SJean-Baptiste Boric 	size_t new_filesize = old_filesize + sz;
398*9f988b79SJean-Baptiste Boric 	struct v7fs_daddr_map oldmap, newmap;
399*9f988b79SJean-Baptiste Boric 	v7fs_daddr_t blk, idxblk;
400*9f988b79SJean-Baptiste Boric 	int error;
401*9f988b79SJean-Baptiste Boric 	v7fs_daddr_t old_nblk = V7FS_ROUND_BSIZE(old_filesize) >> V7FS_BSHIFT;
402*9f988b79SJean-Baptiste Boric 	v7fs_daddr_t new_nblk = V7FS_ROUND_BSIZE(new_filesize) >> V7FS_BSHIFT;
403*9f988b79SJean-Baptiste Boric 
404*9f988b79SJean-Baptiste Boric 	if (old_nblk == new_nblk) {
405*9f988b79SJean-Baptiste Boric 		inode->filesize += sz;
406*9f988b79SJean-Baptiste Boric 		v7fs_inode_writeback(fs, inode);
407*9f988b79SJean-Baptiste Boric 		return 0; /* no need to expand. */
408*9f988b79SJean-Baptiste Boric 	}
409*9f988b79SJean-Baptiste Boric 	struct v7fs_inode backup = *inode;
410*9f988b79SJean-Baptiste Boric 	v7fs_daddr_t required_blk = new_nblk - old_nblk;
411*9f988b79SJean-Baptiste Boric 
412*9f988b79SJean-Baptiste Boric 	DPRINTF("%zu->%zu, required block=%d\n", old_filesize, new_filesize,
413*9f988b79SJean-Baptiste Boric 	    required_blk);
414*9f988b79SJean-Baptiste Boric 
415*9f988b79SJean-Baptiste Boric 	v7fs_datablock_addr(old_filesize, &oldmap);
416*9f988b79SJean-Baptiste Boric 	v7fs_daddr_t i;
417*9f988b79SJean-Baptiste Boric 	for (i = 0; i < required_blk; i++) {
418*9f988b79SJean-Baptiste Boric 		v7fs_datablock_addr(old_filesize + (i+1) * V7FS_BSIZE, &newmap);
419*9f988b79SJean-Baptiste Boric 		daddr_map_dump(&oldmap);
420*9f988b79SJean-Baptiste Boric 		daddr_map_dump(&newmap);
421*9f988b79SJean-Baptiste Boric 
422*9f988b79SJean-Baptiste Boric 		if (oldmap.level != newmap.level) {
423*9f988b79SJean-Baptiste Boric 			/* Allocate index area */
424*9f988b79SJean-Baptiste Boric 			if ((error = v7fs_datablock_allocate(fs, &idxblk)))
425*9f988b79SJean-Baptiste Boric 				return error;
426*9f988b79SJean-Baptiste Boric 
427*9f988b79SJean-Baptiste Boric 			switch (newmap.level) {
428*9f988b79SJean-Baptiste Boric 			case 1:
429*9f988b79SJean-Baptiste Boric 				DPRINTF("0->1\n");
430*9f988b79SJean-Baptiste Boric 				inode->addr[V7FS_NADDR_INDEX1] = idxblk;
431*9f988b79SJean-Baptiste Boric 				blk = v7fs_add_leaf(fs, idxblk, 0);
432*9f988b79SJean-Baptiste Boric 				break;
433*9f988b79SJean-Baptiste Boric 			case 2:
434*9f988b79SJean-Baptiste Boric 				DPRINTF("1->2\n");
435*9f988b79SJean-Baptiste Boric 				inode->addr[V7FS_NADDR_INDEX2] = idxblk;
436*9f988b79SJean-Baptiste Boric 				blk = v7fs_add_leaf(fs, v7fs_add_leaf(fs,
437*9f988b79SJean-Baptiste Boric 				    idxblk, 0), 0);
438*9f988b79SJean-Baptiste Boric 				break;
439*9f988b79SJean-Baptiste Boric 			case 3:
440*9f988b79SJean-Baptiste Boric 				DPRINTF("2->3\n");
441*9f988b79SJean-Baptiste Boric 				inode->addr[V7FS_NADDR_INDEX3] = idxblk;
442*9f988b79SJean-Baptiste Boric 				blk = v7fs_add_leaf(fs, v7fs_add_leaf(fs,
443*9f988b79SJean-Baptiste Boric 				    v7fs_add_leaf(fs, idxblk, 0), 0), 0);
444*9f988b79SJean-Baptiste Boric 				break;
445*9f988b79SJean-Baptiste Boric 			}
446*9f988b79SJean-Baptiste Boric 		} else {
447*9f988b79SJean-Baptiste Boric 			switch (newmap.level) {
448*9f988b79SJean-Baptiste Boric 			case 0:
449*9f988b79SJean-Baptiste Boric 				if ((error = v7fs_datablock_allocate(fs, &blk)))
450*9f988b79SJean-Baptiste Boric 					return error;
451*9f988b79SJean-Baptiste Boric 				inode->addr[newmap.index[0]] = blk;
452*9f988b79SJean-Baptiste Boric 				DPRINTF("direct index %d = blk%d\n",
453*9f988b79SJean-Baptiste Boric 				    newmap.index[0], blk);
454*9f988b79SJean-Baptiste Boric 				break;
455*9f988b79SJean-Baptiste Boric 			case 1:
456*9f988b79SJean-Baptiste Boric 				idxblk = inode->addr[V7FS_NADDR_INDEX1];
457*9f988b79SJean-Baptiste Boric 				blk = v7fs_add_leaf(fs, idxblk,
458*9f988b79SJean-Baptiste Boric 				    newmap.index[0]);
459*9f988b79SJean-Baptiste Boric 				break;
460*9f988b79SJean-Baptiste Boric 			case 2:
461*9f988b79SJean-Baptiste Boric 				idxblk = inode->addr[V7FS_NADDR_INDEX2];
462*9f988b79SJean-Baptiste Boric 				if (oldmap.index[0] != newmap.index[0]) {
463*9f988b79SJean-Baptiste Boric 					v7fs_add_leaf(fs, idxblk,
464*9f988b79SJean-Baptiste Boric 					    newmap.index[0]);
465*9f988b79SJean-Baptiste Boric 				}
466*9f988b79SJean-Baptiste Boric 				blk = v7fs_add_leaf(fs, v7fs_link(fs,idxblk,
467*9f988b79SJean-Baptiste Boric 				    newmap.index[0]), newmap.index[1]);
468*9f988b79SJean-Baptiste Boric 				break;
469*9f988b79SJean-Baptiste Boric 			case 3:
470*9f988b79SJean-Baptiste Boric 				idxblk = inode->addr[V7FS_NADDR_INDEX3];
471*9f988b79SJean-Baptiste Boric 
472*9f988b79SJean-Baptiste Boric 				if (oldmap.index[0] != newmap.index[0]) {
473*9f988b79SJean-Baptiste Boric 					v7fs_add_leaf(fs, idxblk,
474*9f988b79SJean-Baptiste Boric 					    newmap.index[0]);
475*9f988b79SJean-Baptiste Boric 				}
476*9f988b79SJean-Baptiste Boric 
477*9f988b79SJean-Baptiste Boric 				if (oldmap.index[1] != newmap.index[1]) {
478*9f988b79SJean-Baptiste Boric 					v7fs_add_leaf(fs, v7fs_link(fs, idxblk,
479*9f988b79SJean-Baptiste Boric 					    newmap.index[0]), newmap.index[1]);
480*9f988b79SJean-Baptiste Boric 				}
481*9f988b79SJean-Baptiste Boric 				blk = v7fs_add_leaf(fs, v7fs_link(fs,
482*9f988b79SJean-Baptiste Boric 				    v7fs_link(fs, idxblk, newmap.index[0]),
483*9f988b79SJean-Baptiste Boric 				    newmap.index[1]), newmap.index[2]);
484*9f988b79SJean-Baptiste Boric 				break;
485*9f988b79SJean-Baptiste Boric 			}
486*9f988b79SJean-Baptiste Boric 		}
487*9f988b79SJean-Baptiste Boric 		if (!blk) {
488*9f988b79SJean-Baptiste Boric 			*inode = backup; /* structure copy; */
489*9f988b79SJean-Baptiste Boric 			return ENOSPC;
490*9f988b79SJean-Baptiste Boric 		}
491*9f988b79SJean-Baptiste Boric 		oldmap = newmap;
492*9f988b79SJean-Baptiste Boric 	}
493*9f988b79SJean-Baptiste Boric 	inode->filesize += sz;
494*9f988b79SJean-Baptiste Boric 	v7fs_inode_writeback(fs, inode);
495*9f988b79SJean-Baptiste Boric 
496*9f988b79SJean-Baptiste Boric 	return 0;
497*9f988b79SJean-Baptiste Boric }
498*9f988b79SJean-Baptiste Boric 
499*9f988b79SJean-Baptiste Boric static v7fs_daddr_t
v7fs_link(struct v7fs_self * fs,v7fs_daddr_t listblk,int n)500*9f988b79SJean-Baptiste Boric v7fs_link(struct v7fs_self *fs, v7fs_daddr_t listblk, int n)
501*9f988b79SJean-Baptiste Boric {
502*9f988b79SJean-Baptiste Boric 	v7fs_daddr_t *list;
503*9f988b79SJean-Baptiste Boric 	v7fs_daddr_t blk;
504*9f988b79SJean-Baptiste Boric 	void *buf;
505*9f988b79SJean-Baptiste Boric 
506*9f988b79SJean-Baptiste Boric 	if (!datablock_number_sanity(fs, listblk))
507*9f988b79SJean-Baptiste Boric 		return 0;
508*9f988b79SJean-Baptiste Boric 	if (!(buf = scratch_read(fs, listblk)))
509*9f988b79SJean-Baptiste Boric 		return 0;
510*9f988b79SJean-Baptiste Boric 	list = (v7fs_daddr_t *)buf;
511*9f988b79SJean-Baptiste Boric 	blk = V7FS_VAL32(fs, list[n]);
512*9f988b79SJean-Baptiste Boric 	scratch_free(fs, buf);
513*9f988b79SJean-Baptiste Boric 
514*9f988b79SJean-Baptiste Boric 	if (!datablock_number_sanity(fs, blk))
515*9f988b79SJean-Baptiste Boric 		return 0;
516*9f988b79SJean-Baptiste Boric 
517*9f988b79SJean-Baptiste Boric 	return blk;
518*9f988b79SJean-Baptiste Boric }
519*9f988b79SJean-Baptiste Boric 
520*9f988b79SJean-Baptiste Boric static v7fs_daddr_t
v7fs_add_leaf(struct v7fs_self * fs,v7fs_daddr_t up,int idx)521*9f988b79SJean-Baptiste Boric v7fs_add_leaf(struct v7fs_self *fs, v7fs_daddr_t up, int idx)
522*9f988b79SJean-Baptiste Boric {
523*9f988b79SJean-Baptiste Boric 	v7fs_daddr_t newblk;
524*9f988b79SJean-Baptiste Boric 	v7fs_daddr_t *daddr_list;
525*9f988b79SJean-Baptiste Boric 	int error = 0;
526*9f988b79SJean-Baptiste Boric 	void *buf;
527*9f988b79SJean-Baptiste Boric 
528*9f988b79SJean-Baptiste Boric 	if (!up)
529*9f988b79SJean-Baptiste Boric 		return 0;
530*9f988b79SJean-Baptiste Boric 	if (!datablock_number_sanity(fs, up))
531*9f988b79SJean-Baptiste Boric 		return 0;
532*9f988b79SJean-Baptiste Boric 
533*9f988b79SJean-Baptiste Boric 	if ((error = v7fs_datablock_allocate(fs, &newblk)))
534*9f988b79SJean-Baptiste Boric 		return 0;
535*9f988b79SJean-Baptiste Boric 	if (!(buf = scratch_read(fs, up)))
536*9f988b79SJean-Baptiste Boric 		return 0;
537*9f988b79SJean-Baptiste Boric 	daddr_list = (v7fs_daddr_t *)buf;
538*9f988b79SJean-Baptiste Boric 	daddr_list[idx] = V7FS_VAL32(fs, newblk);
539*9f988b79SJean-Baptiste Boric 	if (!fs->io.write(fs->io.cookie, buf, up))
540*9f988b79SJean-Baptiste Boric 		newblk = 0;
541*9f988b79SJean-Baptiste Boric 	scratch_free(fs, buf);
542*9f988b79SJean-Baptiste Boric 
543*9f988b79SJean-Baptiste Boric 	return newblk;
544*9f988b79SJean-Baptiste Boric }
545*9f988b79SJean-Baptiste Boric 
546*9f988b79SJean-Baptiste Boric int
v7fs_datablock_contract(struct v7fs_self * fs,struct v7fs_inode * inode,size_t sz)547*9f988b79SJean-Baptiste Boric v7fs_datablock_contract(struct v7fs_self *fs, struct v7fs_inode *inode,
548*9f988b79SJean-Baptiste Boric     size_t sz)
549*9f988b79SJean-Baptiste Boric {
550*9f988b79SJean-Baptiste Boric 	size_t old_filesize = inode->filesize;
551*9f988b79SJean-Baptiste Boric 	size_t new_filesize = old_filesize - sz;
552*9f988b79SJean-Baptiste Boric 	struct v7fs_daddr_map oldmap, newmap;
553*9f988b79SJean-Baptiste Boric 	v7fs_daddr_t blk, idxblk;
554*9f988b79SJean-Baptiste Boric 	int error = 0;
555*9f988b79SJean-Baptiste Boric 	v7fs_daddr_t old_nblk = V7FS_ROUND_BSIZE(old_filesize) >> V7FS_BSHIFT;
556*9f988b79SJean-Baptiste Boric 	v7fs_daddr_t new_nblk = V7FS_ROUND_BSIZE(new_filesize) >> V7FS_BSHIFT;
557*9f988b79SJean-Baptiste Boric 
558*9f988b79SJean-Baptiste Boric 	if (old_nblk == new_nblk) {
559*9f988b79SJean-Baptiste Boric 		inode->filesize -= sz;
560*9f988b79SJean-Baptiste Boric 		v7fs_inode_writeback(fs, inode);
561*9f988b79SJean-Baptiste Boric 		return 0; /* no need to contract; */
562*9f988b79SJean-Baptiste Boric 	}
563*9f988b79SJean-Baptiste Boric 	v7fs_daddr_t erase_blk = old_nblk - new_nblk;
564*9f988b79SJean-Baptiste Boric 
565*9f988b79SJean-Baptiste Boric 	DPRINTF("%zu->%zu # of erased block=%d\n", old_filesize, new_filesize,
566*9f988b79SJean-Baptiste Boric 	    erase_blk);
567*9f988b79SJean-Baptiste Boric 
568*9f988b79SJean-Baptiste Boric 	v7fs_datablock_addr(old_filesize, &oldmap);
569*9f988b79SJean-Baptiste Boric 	v7fs_daddr_t i;
570*9f988b79SJean-Baptiste Boric 	for (i = 0; i < erase_blk; i++) {
571*9f988b79SJean-Baptiste Boric 		v7fs_datablock_addr(old_filesize - (i+1) * V7FS_BSIZE, &newmap);
572*9f988b79SJean-Baptiste Boric 
573*9f988b79SJean-Baptiste Boric 		if (oldmap.level != newmap.level) {
574*9f988b79SJean-Baptiste Boric 			switch (newmap.level) {
575*9f988b79SJean-Baptiste Boric 			case 0: /*1->0 */
576*9f988b79SJean-Baptiste Boric 				DPRINTF("1->0\n");
577*9f988b79SJean-Baptiste Boric 				idxblk = inode->addr[V7FS_NADDR_INDEX1];
578*9f988b79SJean-Baptiste Boric 				inode->addr[V7FS_NADDR_INDEX1] = 0;
579*9f988b79SJean-Baptiste Boric 				error = v7fs_datablock_deallocate(fs,
580*9f988b79SJean-Baptiste Boric 				    v7fs_remove_self(fs, idxblk));
581*9f988b79SJean-Baptiste Boric 				break;
582*9f988b79SJean-Baptiste Boric 			case 1: /*2->1 */
583*9f988b79SJean-Baptiste Boric 				DPRINTF("2->1\n");
584*9f988b79SJean-Baptiste Boric 				idxblk = inode->addr[V7FS_NADDR_INDEX2];
585*9f988b79SJean-Baptiste Boric 				inode->addr[V7FS_NADDR_INDEX2] = 0;
586*9f988b79SJean-Baptiste Boric 				error = v7fs_datablock_deallocate(fs,
587*9f988b79SJean-Baptiste Boric 				    v7fs_remove_self(fs, v7fs_remove_self(fs,
588*9f988b79SJean-Baptiste Boric 				    idxblk)));
589*9f988b79SJean-Baptiste Boric 				break;
590*9f988b79SJean-Baptiste Boric 			case 2:/*3->2 */
591*9f988b79SJean-Baptiste Boric 				DPRINTF("3->2\n");
592*9f988b79SJean-Baptiste Boric 				idxblk = inode->addr[V7FS_NADDR_INDEX3];
593*9f988b79SJean-Baptiste Boric 				inode->addr[V7FS_NADDR_INDEX3] = 0;
594*9f988b79SJean-Baptiste Boric 				error = v7fs_datablock_deallocate(fs,
595*9f988b79SJean-Baptiste Boric 				    v7fs_remove_self(fs, v7fs_remove_self(fs,
596*9f988b79SJean-Baptiste Boric 					v7fs_remove_self(fs, idxblk))));
597*9f988b79SJean-Baptiste Boric 				break;
598*9f988b79SJean-Baptiste Boric 			}
599*9f988b79SJean-Baptiste Boric 		} else {
600*9f988b79SJean-Baptiste Boric 			switch (newmap.level) {
601*9f988b79SJean-Baptiste Boric 			case 0:
602*9f988b79SJean-Baptiste Boric 				DPRINTF("[0] %d\n", oldmap.index[0]);
603*9f988b79SJean-Baptiste Boric 				blk = inode->addr[oldmap.index[0]];
604*9f988b79SJean-Baptiste Boric 				error = v7fs_datablock_deallocate(fs, blk);
605*9f988b79SJean-Baptiste Boric 				break;
606*9f988b79SJean-Baptiste Boric 			case 1:
607*9f988b79SJean-Baptiste Boric 				DPRINTF("[1] %d\n", oldmap.index[0]);
608*9f988b79SJean-Baptiste Boric 				idxblk = inode->addr[V7FS_NADDR_INDEX1];
609*9f988b79SJean-Baptiste Boric 				v7fs_remove_leaf(fs, idxblk, oldmap.index[0]);
610*9f988b79SJean-Baptiste Boric 
611*9f988b79SJean-Baptiste Boric 				break;
612*9f988b79SJean-Baptiste Boric 			case 2:
613*9f988b79SJean-Baptiste Boric 				DPRINTF("[2] %d %d\n", oldmap.index[0],
614*9f988b79SJean-Baptiste Boric 				    oldmap.index[1]);
615*9f988b79SJean-Baptiste Boric 				idxblk = inode->addr[V7FS_NADDR_INDEX2];
616*9f988b79SJean-Baptiste Boric 				v7fs_remove_leaf(fs, v7fs_link(fs, idxblk,
617*9f988b79SJean-Baptiste Boric 				    oldmap.index[0]), oldmap.index[1]);
618*9f988b79SJean-Baptiste Boric 				if (oldmap.index[0] != newmap.index[0]) {
619*9f988b79SJean-Baptiste Boric 					v7fs_remove_leaf(fs, idxblk,
620*9f988b79SJean-Baptiste Boric 					    oldmap.index[0]);
621*9f988b79SJean-Baptiste Boric 				}
622*9f988b79SJean-Baptiste Boric 				break;
623*9f988b79SJean-Baptiste Boric 			case 3:
624*9f988b79SJean-Baptiste Boric 				DPRINTF("[2] %d %d %d\n", oldmap.index[0],
625*9f988b79SJean-Baptiste Boric 				    oldmap.index[1], oldmap.index[2]);
626*9f988b79SJean-Baptiste Boric 				idxblk = inode->addr[V7FS_NADDR_INDEX3];
627*9f988b79SJean-Baptiste Boric 				v7fs_remove_leaf(fs, v7fs_link(fs,
628*9f988b79SJean-Baptiste Boric 				    v7fs_link(fs, idxblk, oldmap.index[0]),
629*9f988b79SJean-Baptiste Boric 				    oldmap.index[1]), oldmap.index[2]);
630*9f988b79SJean-Baptiste Boric 
631*9f988b79SJean-Baptiste Boric 				if (oldmap.index[1] != newmap.index[1])	{
632*9f988b79SJean-Baptiste Boric 					v7fs_remove_leaf(fs, v7fs_link(fs,
633*9f988b79SJean-Baptiste Boric 					    idxblk, oldmap.index[0]),
634*9f988b79SJean-Baptiste Boric 					    oldmap.index[1]);
635*9f988b79SJean-Baptiste Boric 				}
636*9f988b79SJean-Baptiste Boric 				if (oldmap.index[0] != newmap.index[0]) {
637*9f988b79SJean-Baptiste Boric 					v7fs_remove_leaf(fs, idxblk,
638*9f988b79SJean-Baptiste Boric 					    oldmap.index[0]);
639*9f988b79SJean-Baptiste Boric 				}
640*9f988b79SJean-Baptiste Boric 				break;
641*9f988b79SJean-Baptiste Boric 			}
642*9f988b79SJean-Baptiste Boric 		}
643*9f988b79SJean-Baptiste Boric 		oldmap = newmap;
644*9f988b79SJean-Baptiste Boric 	}
645*9f988b79SJean-Baptiste Boric 	inode->filesize -= sz;
646*9f988b79SJean-Baptiste Boric 	v7fs_inode_writeback(fs, inode);
647*9f988b79SJean-Baptiste Boric 
648*9f988b79SJean-Baptiste Boric 	return error;
649*9f988b79SJean-Baptiste Boric }
650*9f988b79SJean-Baptiste Boric 
651*9f988b79SJean-Baptiste Boric static v7fs_daddr_t
v7fs_unlink(struct v7fs_self * fs,v7fs_daddr_t idxblk,int n)652*9f988b79SJean-Baptiste Boric v7fs_unlink(struct v7fs_self *fs, v7fs_daddr_t idxblk, int n)
653*9f988b79SJean-Baptiste Boric {
654*9f988b79SJean-Baptiste Boric 	v7fs_daddr_t *daddr_list;
655*9f988b79SJean-Baptiste Boric 	v7fs_daddr_t blk;
656*9f988b79SJean-Baptiste Boric 	void *buf;
657*9f988b79SJean-Baptiste Boric 
658*9f988b79SJean-Baptiste Boric 	if (!(buf = scratch_read(fs, idxblk)))
659*9f988b79SJean-Baptiste Boric 		return 0;
660*9f988b79SJean-Baptiste Boric 	daddr_list = (v7fs_daddr_t *)buf;
661*9f988b79SJean-Baptiste Boric 	blk = V7FS_VAL32(fs, daddr_list[n]);
662*9f988b79SJean-Baptiste Boric 	daddr_list[n] = 0;
663*9f988b79SJean-Baptiste Boric 	fs->io.write(fs->io.cookie, buf, idxblk);
664*9f988b79SJean-Baptiste Boric 	scratch_free(fs, buf);
665*9f988b79SJean-Baptiste Boric 
666*9f988b79SJean-Baptiste Boric 	return blk; /* unlinked block. */
667*9f988b79SJean-Baptiste Boric }
668*9f988b79SJean-Baptiste Boric 
669*9f988b79SJean-Baptiste Boric static v7fs_daddr_t
v7fs_remove_self(struct v7fs_self * fs,v7fs_daddr_t up)670*9f988b79SJean-Baptiste Boric v7fs_remove_self(struct v7fs_self *fs, v7fs_daddr_t up)
671*9f988b79SJean-Baptiste Boric {
672*9f988b79SJean-Baptiste Boric 	v7fs_daddr_t down;
673*9f988b79SJean-Baptiste Boric 
674*9f988b79SJean-Baptiste Boric 	if (!datablock_number_sanity(fs, up))
675*9f988b79SJean-Baptiste Boric 		return 0;
676*9f988b79SJean-Baptiste Boric 
677*9f988b79SJean-Baptiste Boric 	/* At 1st, remove from datablock list. */
678*9f988b79SJean-Baptiste Boric 	down = v7fs_unlink(fs, up, 0);
679*9f988b79SJean-Baptiste Boric 
680*9f988b79SJean-Baptiste Boric 	/* link self to freelist. */
681*9f988b79SJean-Baptiste Boric 	v7fs_datablock_deallocate(fs, up);
682*9f988b79SJean-Baptiste Boric 
683*9f988b79SJean-Baptiste Boric 	return down;
684*9f988b79SJean-Baptiste Boric }
685*9f988b79SJean-Baptiste Boric 
686*9f988b79SJean-Baptiste Boric static v7fs_daddr_t
v7fs_remove_leaf(struct v7fs_self * fs,v7fs_daddr_t up,int n)687*9f988b79SJean-Baptiste Boric v7fs_remove_leaf(struct v7fs_self *fs, v7fs_daddr_t up, int n)
688*9f988b79SJean-Baptiste Boric {
689*9f988b79SJean-Baptiste Boric 	v7fs_daddr_t down;
690*9f988b79SJean-Baptiste Boric 
691*9f988b79SJean-Baptiste Boric 	if (!datablock_number_sanity(fs, up))
692*9f988b79SJean-Baptiste Boric 		return 0;
693*9f988b79SJean-Baptiste Boric 
694*9f988b79SJean-Baptiste Boric 	/* At 1st, remove from datablock list. */
695*9f988b79SJean-Baptiste Boric 	down = v7fs_unlink(fs, up, n);
696*9f988b79SJean-Baptiste Boric 
697*9f988b79SJean-Baptiste Boric 	/* link leaf to freelist. */
698*9f988b79SJean-Baptiste Boric 	v7fs_datablock_deallocate(fs, down);
699*9f988b79SJean-Baptiste Boric 
700*9f988b79SJean-Baptiste Boric 	return down;
701*9f988b79SJean-Baptiste Boric }
702*9f988b79SJean-Baptiste Boric 
703*9f988b79SJean-Baptiste Boric int
v7fs_datablock_size_change(struct v7fs_self * fs,size_t newsz,struct v7fs_inode * inode)704*9f988b79SJean-Baptiste Boric v7fs_datablock_size_change(struct v7fs_self *fs, size_t newsz,
705*9f988b79SJean-Baptiste Boric     struct v7fs_inode *inode)
706*9f988b79SJean-Baptiste Boric {
707*9f988b79SJean-Baptiste Boric 	ssize_t diff = newsz - v7fs_inode_filesize(inode);
708*9f988b79SJean-Baptiste Boric 	int error = 0;
709*9f988b79SJean-Baptiste Boric 
710*9f988b79SJean-Baptiste Boric 	if (diff > 0)
711*9f988b79SJean-Baptiste Boric 		error = v7fs_datablock_expand(fs, inode, diff);
712*9f988b79SJean-Baptiste Boric 	else if (diff < 0)
713*9f988b79SJean-Baptiste Boric 		error = v7fs_datablock_contract(fs, inode, -diff);
714*9f988b79SJean-Baptiste Boric 
715*9f988b79SJean-Baptiste Boric 	return error;
716*9f988b79SJean-Baptiste Boric }
717*9f988b79SJean-Baptiste Boric 
718*9f988b79SJean-Baptiste Boric #ifdef V7FS_DATABLOCK_DEBUG
719*9f988b79SJean-Baptiste Boric void
daddr_map_dump(const struct v7fs_daddr_map * map)720*9f988b79SJean-Baptiste Boric daddr_map_dump(const struct v7fs_daddr_map *map)
721*9f988b79SJean-Baptiste Boric {
722*9f988b79SJean-Baptiste Boric 
723*9f988b79SJean-Baptiste Boric 	DPRINTF("level %d ", map->level);
724*9f988b79SJean-Baptiste Boric 	int m, n = !map->level ? 1 : map->level;
725*9f988b79SJean-Baptiste Boric 	for (m = 0; m < n; m++)
726*9f988b79SJean-Baptiste Boric 		printf("[%d]", map->index[m]);
727*9f988b79SJean-Baptiste Boric 	printf("\n");
728*9f988b79SJean-Baptiste Boric }
729*9f988b79SJean-Baptiste Boric #endif
730