Deleted Added
full compact
ext2_alloc.c (59259) ext2_alloc.c (72640)
1/*
2 * modified for Lites 1.1
3 *
4 * Aug 1995, Godmar Back (gback@cs.utah.edu)
5 * University of Utah, Department of Computer Science
6 */
7/*
8 * Copyright (c) 1982, 1986, 1989, 1993
9 * The Regents of the University of California. All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 * @(#)ext2_alloc.c 8.8 (Berkeley) 2/21/94
1/*
2 * modified for Lites 1.1
3 *
4 * Aug 1995, Godmar Back (gback@cs.utah.edu)
5 * University of Utah, Department of Computer Science
6 */
7/*
8 * Copyright (c) 1982, 1986, 1989, 1993
9 * The Regents of the University of California. All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 * @(#)ext2_alloc.c 8.8 (Berkeley) 2/21/94
40 * $FreeBSD: head/sys/gnu/fs/ext2fs/ext2_alloc.c 59259 2000-04-15 17:14:22Z rwatson $
40 * $FreeBSD: head/sys/gnu/fs/ext2fs/ext2_alloc.c 72640 2001-02-18 10:25:42Z asmodai $
41 */
42
43#include "opt_quota.h"
44
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/conf.h>
48#include <sys/vnode.h>
49#include <sys/stat.h>
50#include <sys/mount.h>
51#include <sys/syslog.h>
52
53#include <ufs/ufs/extattr.h>
54#include <ufs/ufs/quota.h>
55#include <ufs/ufs/inode.h>
56#include <ufs/ufs/ufsmount.h>
57
58#include <gnu/ext2fs/ext2_fs.h>
59#include <gnu/ext2fs/ext2_fs_sb.h>
60#include <gnu/ext2fs/fs.h>
61#include <gnu/ext2fs/ext2_extern.h>
62
63static void ext2_fserr __P((struct ext2_sb_info *, u_int, char *));
64
65/*
66 * Linux calls this functions at the following locations:
67 * (1) the inode is freed
68 * (2) a preallocation miss occurs
69 * (3) truncate is called
70 * (4) release_file is called and f_mode & 2
71 *
72 * I call it in ext2_inactive, ext2_truncate, ext2_vfree and in (2)
73 * the call in vfree might be redundant
74 */
75void
76ext2_discard_prealloc(ip)
77 struct inode * ip;
78{
79#ifdef EXT2_PREALLOCATE
80 if (ip->i_prealloc_count) {
81 int i = ip->i_prealloc_count;
82 ip->i_prealloc_count = 0;
83 ext2_free_blocks (ITOV(ip)->v_mount,
84 ip->i_prealloc_block,
85 i);
86 }
87#endif
88}
89
90/*
91 * Allocate a block in the file system.
92 *
93 * this takes the framework from ffs_alloc. To implement the
94 * actual allocation, it calls ext2_new_block, the ported version
95 * of the same Linux routine.
96 *
97 * we note that this is always called in connection with ext2_blkpref
98 *
99 * preallocation is done as Linux does it
100 */
101int
102ext2_alloc(ip, lbn, bpref, size, cred, bnp)
103 register struct inode *ip;
104 daddr_t lbn, bpref;
105 int size;
106 struct ucred *cred;
107 daddr_t *bnp;
108{
109 register struct ext2_sb_info *fs;
110 daddr_t bno;
111#if QUOTA
112 int error;
113#endif
114
115 *bnp = 0;
116 fs = ip->i_e2fs;
117#if DIAGNOSTIC
118 if ((u_int)size > fs->s_blocksize || blkoff(fs, size) != 0) {
119 printf("dev = %s, bsize = %lu, size = %d, fs = %s\n",
120 devtoname(ip->i_dev), fs->s_blocksize, size, fs->fs_fsmnt);
121 panic("ext2_alloc: bad size");
122 }
123 if (cred == NOCRED)
124 panic("ext2_alloc: missing credential");
125#endif /* DIAGNOSTIC */
126 if (size == fs->s_blocksize && fs->s_es->s_free_blocks_count == 0)
127 goto nospace;
128 if (cred->cr_uid != 0 &&
129 fs->s_es->s_free_blocks_count < fs->s_es->s_r_blocks_count)
130 goto nospace;
131#if QUOTA
132 if ((error = chkdq(ip, (long)btodb(size), cred, 0)) != 0)
133 return (error);
134#endif
135 if (bpref >= fs->s_es->s_blocks_count)
136 bpref = 0;
137 /* call the Linux code */
138#ifdef EXT2_PREALLOCATE
139 /* To have a preallocation hit, we must
140 * - have at least one block preallocated
141 * - and our preferred block must have that block number or one below
142 */
143 if (ip->i_prealloc_count &&
144 (bpref == ip->i_prealloc_block ||
145 bpref + 1 == ip->i_prealloc_block))
146 {
147 bno = ip->i_prealloc_block++;
148 ip->i_prealloc_count--;
149 /* ext2_debug ("preallocation hit (%lu/%lu).\n",
150 ++alloc_hits, ++alloc_attempts); */
151
152 /* Linux gets, clears, and releases the buffer at this
153 point - we don't have to that; we leave it to the caller
154 */
155 } else {
156 ext2_discard_prealloc (ip);
157 /* ext2_debug ("preallocation miss (%lu/%lu).\n",
158 alloc_hits, ++alloc_attempts); */
159 if (S_ISREG(ip->i_mode))
160 bno = ext2_new_block
161 (ITOV(ip)->v_mount, bpref,
162 &ip->i_prealloc_count,
163 &ip->i_prealloc_block);
164 else
165 bno = (daddr_t)ext2_new_block(ITOV(ip)->v_mount,
166 bpref, 0, 0);
167 }
168#else
169 bno = (daddr_t)ext2_new_block(ITOV(ip)->v_mount, bpref, 0, 0);
170#endif
171
172 if (bno > 0) {
173 /* set next_alloc fields as done in block_getblk */
174 ip->i_next_alloc_block = lbn;
175 ip->i_next_alloc_goal = bno;
176
177 ip->i_blocks += btodb(size);
178 ip->i_flag |= IN_CHANGE | IN_UPDATE;
179 *bnp = bno;
180 return (0);
181 }
182#if QUOTA
183 /*
184 * Restore user's disk quota because allocation failed.
185 */
186 (void) chkdq(ip, (long)-btodb(size), cred, FORCE);
187#endif
188nospace:
189 ext2_fserr(fs, cred->cr_uid, "file system full");
190 uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt);
191 return (ENOSPC);
192}
193
194/*
195 * Reallocate a sequence of blocks into a contiguous sequence of blocks.
196 *
197 * The vnode and an array of buffer pointers for a range of sequential
198 * logical blocks to be made contiguous is given. The allocator attempts
199 * to find a range of sequential blocks starting as close as possible to
200 * an fs_rotdelay offset from the end of the allocation for the logical
41 */
42
43#include "opt_quota.h"
44
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/conf.h>
48#include <sys/vnode.h>
49#include <sys/stat.h>
50#include <sys/mount.h>
51#include <sys/syslog.h>
52
53#include <ufs/ufs/extattr.h>
54#include <ufs/ufs/quota.h>
55#include <ufs/ufs/inode.h>
56#include <ufs/ufs/ufsmount.h>
57
58#include <gnu/ext2fs/ext2_fs.h>
59#include <gnu/ext2fs/ext2_fs_sb.h>
60#include <gnu/ext2fs/fs.h>
61#include <gnu/ext2fs/ext2_extern.h>
62
63static void ext2_fserr __P((struct ext2_sb_info *, u_int, char *));
64
65/*
66 * Linux calls this functions at the following locations:
67 * (1) the inode is freed
68 * (2) a preallocation miss occurs
69 * (3) truncate is called
70 * (4) release_file is called and f_mode & 2
71 *
72 * I call it in ext2_inactive, ext2_truncate, ext2_vfree and in (2)
73 * the call in vfree might be redundant
74 */
75void
76ext2_discard_prealloc(ip)
77 struct inode * ip;
78{
79#ifdef EXT2_PREALLOCATE
80 if (ip->i_prealloc_count) {
81 int i = ip->i_prealloc_count;
82 ip->i_prealloc_count = 0;
83 ext2_free_blocks (ITOV(ip)->v_mount,
84 ip->i_prealloc_block,
85 i);
86 }
87#endif
88}
89
90/*
91 * Allocate a block in the file system.
92 *
93 * this takes the framework from ffs_alloc. To implement the
94 * actual allocation, it calls ext2_new_block, the ported version
95 * of the same Linux routine.
96 *
97 * we note that this is always called in connection with ext2_blkpref
98 *
99 * preallocation is done as Linux does it
100 */
101int
102ext2_alloc(ip, lbn, bpref, size, cred, bnp)
103 register struct inode *ip;
104 daddr_t lbn, bpref;
105 int size;
106 struct ucred *cred;
107 daddr_t *bnp;
108{
109 register struct ext2_sb_info *fs;
110 daddr_t bno;
111#if QUOTA
112 int error;
113#endif
114
115 *bnp = 0;
116 fs = ip->i_e2fs;
117#if DIAGNOSTIC
118 if ((u_int)size > fs->s_blocksize || blkoff(fs, size) != 0) {
119 printf("dev = %s, bsize = %lu, size = %d, fs = %s\n",
120 devtoname(ip->i_dev), fs->s_blocksize, size, fs->fs_fsmnt);
121 panic("ext2_alloc: bad size");
122 }
123 if (cred == NOCRED)
124 panic("ext2_alloc: missing credential");
125#endif /* DIAGNOSTIC */
126 if (size == fs->s_blocksize && fs->s_es->s_free_blocks_count == 0)
127 goto nospace;
128 if (cred->cr_uid != 0 &&
129 fs->s_es->s_free_blocks_count < fs->s_es->s_r_blocks_count)
130 goto nospace;
131#if QUOTA
132 if ((error = chkdq(ip, (long)btodb(size), cred, 0)) != 0)
133 return (error);
134#endif
135 if (bpref >= fs->s_es->s_blocks_count)
136 bpref = 0;
137 /* call the Linux code */
138#ifdef EXT2_PREALLOCATE
139 /* To have a preallocation hit, we must
140 * - have at least one block preallocated
141 * - and our preferred block must have that block number or one below
142 */
143 if (ip->i_prealloc_count &&
144 (bpref == ip->i_prealloc_block ||
145 bpref + 1 == ip->i_prealloc_block))
146 {
147 bno = ip->i_prealloc_block++;
148 ip->i_prealloc_count--;
149 /* ext2_debug ("preallocation hit (%lu/%lu).\n",
150 ++alloc_hits, ++alloc_attempts); */
151
152 /* Linux gets, clears, and releases the buffer at this
153 point - we don't have to that; we leave it to the caller
154 */
155 } else {
156 ext2_discard_prealloc (ip);
157 /* ext2_debug ("preallocation miss (%lu/%lu).\n",
158 alloc_hits, ++alloc_attempts); */
159 if (S_ISREG(ip->i_mode))
160 bno = ext2_new_block
161 (ITOV(ip)->v_mount, bpref,
162 &ip->i_prealloc_count,
163 &ip->i_prealloc_block);
164 else
165 bno = (daddr_t)ext2_new_block(ITOV(ip)->v_mount,
166 bpref, 0, 0);
167 }
168#else
169 bno = (daddr_t)ext2_new_block(ITOV(ip)->v_mount, bpref, 0, 0);
170#endif
171
172 if (bno > 0) {
173 /* set next_alloc fields as done in block_getblk */
174 ip->i_next_alloc_block = lbn;
175 ip->i_next_alloc_goal = bno;
176
177 ip->i_blocks += btodb(size);
178 ip->i_flag |= IN_CHANGE | IN_UPDATE;
179 *bnp = bno;
180 return (0);
181 }
182#if QUOTA
183 /*
184 * Restore user's disk quota because allocation failed.
185 */
186 (void) chkdq(ip, (long)-btodb(size), cred, FORCE);
187#endif
188nospace:
189 ext2_fserr(fs, cred->cr_uid, "file system full");
190 uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt);
191 return (ENOSPC);
192}
193
194/*
195 * Reallocate a sequence of blocks into a contiguous sequence of blocks.
196 *
197 * The vnode and an array of buffer pointers for a range of sequential
198 * logical blocks to be made contiguous is given. The allocator attempts
199 * to find a range of sequential blocks starting as close as possible to
200 * an fs_rotdelay offset from the end of the allocation for the logical
201 * block immediately preceeding the current range. If successful, the
201 * block immediately preceding the current range. If successful, the
202 * physical block numbers in the buffer pointers and in the inode are
203 * changed to reflect the new allocation. If unsuccessful, the allocation
204 * is left unchanged. The success in doing the reallocation is returned.
205 * Note that the error return is not reflected back to the user. Rather
206 * the previous block allocation will be used.
207 */
208
209#ifdef FANCY_REALLOC
210#include <sys/sysctl.h>
211static int doasyncfree = 1;
212#ifdef OPT_DEBUG
213SYSCTL_INT(_debug, 14, doasyncfree, CTLFLAG_RW, &doasyncfree, 0, "");
214#endif /* OPT_DEBUG */
215#endif
216
217int
218ext2_reallocblks(ap)
219 struct vop_reallocblks_args /* {
220 struct vnode *a_vp;
221 struct cluster_save *a_buflist;
222 } */ *ap;
223{
224#ifndef FANCY_REALLOC
225/* printf("ext2_reallocblks not implemented\n"); */
226return ENOSPC;
227#else
228
229 struct ext2_sb_info *fs;
230 struct inode *ip;
231 struct vnode *vp;
232 struct buf *sbp, *ebp;
233 daddr_t *bap, *sbap, *ebap;
234 struct cluster_save *buflist;
235 daddr_t start_lbn, end_lbn, soff, eoff, newblk, blkno;
236 struct indir start_ap[NIADDR + 1], end_ap[NIADDR + 1], *idp;
237 int i, len, start_lvl, end_lvl, pref, ssize;
238
239 vp = ap->a_vp;
240 ip = VTOI(vp);
241 fs = ip->i_e2fs;
242#ifdef UNKLAR
243 if (fs->fs_contigsumsize <= 0)
244 return (ENOSPC);
245#endif
246 buflist = ap->a_buflist;
247 len = buflist->bs_nchildren;
248 start_lbn = buflist->bs_children[0]->b_lblkno;
249 end_lbn = start_lbn + len - 1;
250#if DIAGNOSTIC
251 for (i = 1; i < len; i++)
252 if (buflist->bs_children[i]->b_lblkno != start_lbn + i)
253 panic("ext2_reallocblks: non-cluster");
254#endif
255 /*
256 * If the latest allocation is in a new cylinder group, assume that
257 * the filesystem has decided to move and do not force it back to
258 * the previous cylinder group.
259 */
260 if (dtog(fs, dbtofsb(fs, buflist->bs_children[0]->b_blkno)) !=
261 dtog(fs, dbtofsb(fs, buflist->bs_children[len - 1]->b_blkno)))
262 return (ENOSPC);
263 if (ufs_getlbns(vp, start_lbn, start_ap, &start_lvl) ||
264 ufs_getlbns(vp, end_lbn, end_ap, &end_lvl))
265 return (ENOSPC);
266 /*
267 * Get the starting offset and block map for the first block.
268 */
269 if (start_lvl == 0) {
270 sbap = &ip->i_db[0];
271 soff = start_lbn;
272 } else {
273 idp = &start_ap[start_lvl - 1];
274 if (bread(vp, idp->in_lbn, (int)fs->s_blocksize, NOCRED, &sbp)) {
275 brelse(sbp);
276 return (ENOSPC);
277 }
278 sbap = (daddr_t *)sbp->b_data;
279 soff = idp->in_off;
280 }
281 /*
282 * Find the preferred location for the cluster.
283 */
284 pref = ext2_blkpref(ip, start_lbn, soff, sbap);
285 /*
286 * If the block range spans two block maps, get the second map.
287 */
288 if (end_lvl == 0 || (idp = &end_ap[end_lvl - 1])->in_off + 1 >= len) {
289 ssize = len;
290 } else {
291#if DIAGNOSTIC
292 if (start_ap[start_lvl-1].in_lbn == idp->in_lbn)
293 panic("ext2_reallocblk: start == end");
294#endif
295 ssize = len - (idp->in_off + 1);
296 if (bread(vp, idp->in_lbn, (int)fs->s_blocksize, NOCRED, &ebp))
297 goto fail;
298 ebap = (daddr_t *)ebp->b_data;
299 }
300 /*
301 * Search the block map looking for an allocation of the desired size.
302 */
303 if ((newblk = (daddr_t)ext2_hashalloc(ip, dtog(fs, pref), (long)pref,
304 len, (u_long (*)())ext2_clusteralloc)) == 0)
305 goto fail;
306 /*
307 * We have found a new contiguous block.
308 *
309 * First we have to replace the old block pointers with the new
310 * block pointers in the inode and indirect blocks associated
311 * with the file.
312 */
313 blkno = newblk;
314 for (bap = &sbap[soff], i = 0; i < len; i++, blkno += fs->s_frags_per_block) {
315 if (i == ssize)
316 bap = ebap;
317#if DIAGNOSTIC
318 if (buflist->bs_children[i]->b_blkno != fsbtodb(fs, *bap))
319 panic("ext2_reallocblks: alloc mismatch");
320#endif
321 *bap++ = blkno;
322 }
323 /*
324 * Next we must write out the modified inode and indirect blocks.
325 * For strict correctness, the writes should be synchronous since
326 * the old block values may have been written to disk. In practise
327 * they are almost never written, but if we are concerned about
328 * strict correctness, the `doasyncfree' flag should be set to zero.
329 *
330 * The test on `doasyncfree' should be changed to test a flag
331 * that shows whether the associated buffers and inodes have
332 * been written. The flag should be set when the cluster is
333 * started and cleared whenever the buffer or inode is flushed.
334 * We can then check below to see if it is set, and do the
335 * synchronous write only when it has been cleared.
336 */
337 if (sbap != &ip->i_db[0]) {
338 if (doasyncfree)
339 bdwrite(sbp);
340 else
341 bwrite(sbp);
342 } else {
343 ip->i_flag |= IN_CHANGE | IN_UPDATE;
344 if (!doasyncfree)
345 UFS_UPDATE(vp, 1);
346 }
347 if (ssize < len)
348 if (doasyncfree)
349 bdwrite(ebp);
350 else
351 bwrite(ebp);
352 /*
353 * Last, free the old blocks and assign the new blocks to the buffers.
354 */
355 for (blkno = newblk, i = 0; i < len; i++, blkno += fs->s_frags_per_block) {
356 ext2_blkfree(ip, dbtofsb(fs, buflist->bs_children[i]->b_blkno),
357 fs->s_blocksize);
358 buflist->bs_children[i]->b_blkno = fsbtodb(fs, blkno);
359 }
360 return (0);
361
362fail:
363 if (ssize < len)
364 brelse(ebp);
365 if (sbap != &ip->i_db[0])
366 brelse(sbp);
367 return (ENOSPC);
368
369#endif /* FANCY_REALLOC */
370}
371
372/*
373 * Allocate an inode in the file system.
374 *
375 * we leave the actual allocation strategy to the (modified)
376 * ext2_new_inode(), to make sure we get the policies right
377 */
378int
379ext2_valloc(pvp, mode, cred, vpp)
380 struct vnode *pvp;
381 int mode;
382 struct ucred *cred;
383 struct vnode **vpp;
384{
385 register struct inode *pip;
386 register struct ext2_sb_info *fs;
387 register struct inode *ip;
388 ino_t ino;
389 int i, error;
390
391 *vpp = NULL;
392 pip = VTOI(pvp);
393 fs = pip->i_e2fs;
394 if (fs->s_es->s_free_inodes_count == 0)
395 goto noinodes;
396
397 /* call the Linux routine - it returns the inode number only */
398 ino = ext2_new_inode(pip, mode);
399
400 if (ino == 0)
401 goto noinodes;
402 error = VFS_VGET(pvp->v_mount, ino, vpp);
403 if (error) {
404 UFS_VFREE(pvp, ino, mode);
405 return (error);
406 }
407 ip = VTOI(*vpp);
408
409 /*
410 the question is whether using VGET was such good idea at all -
411 Linux doesn't read the old inode in when it's allocating a
412 new one. I will set at least i_size & i_blocks the zero.
413 */
414 ip->i_mode = 0;
415 ip->i_size = 0;
416 ip->i_blocks = 0;
417 ip->i_flags = 0;
418 /* now we want to make sure that the block pointers are zeroed out */
419 for (i = 0; i < NDADDR; i++)
420 ip->i_db[i] = 0;
421 for (i = 0; i < NIADDR; i++)
422 ip->i_ib[i] = 0;
423
424 /*
425 * Set up a new generation number for this inode.
426 * XXX check if this makes sense in ext2
427 */
428 if (ip->i_gen == 0 || ++ip->i_gen == 0)
429 ip->i_gen = random() / 2 + 1;
430/*
431printf("ext2_valloc: allocated inode %d\n", ino);
432*/
433 return (0);
434noinodes:
435 ext2_fserr(fs, cred->cr_uid, "out of inodes");
436 uprintf("\n%s: create/symlink failed, no inodes free\n", fs->fs_fsmnt);
437 return (ENOSPC);
438}
439
440/*
441 * Select the desired position for the next block in a file.
442 *
443 * we try to mimic what Remy does in inode_getblk/block_getblk
444 *
445 * we note: blocknr == 0 means that we're about to allocate either
446 * a direct block or a pointer block at the first level of indirection
447 * (In other words, stuff that will go in i_db[] or i_ib[])
448 *
449 * blocknr != 0 means that we're allocating a block that is none
450 * of the above. Then, blocknr tells us the number of the block
451 * that will hold the pointer
452 */
453daddr_t
454ext2_blkpref(ip, lbn, indx, bap, blocknr)
455 struct inode *ip;
456 daddr_t lbn;
457 int indx;
458 daddr_t *bap;
459 daddr_t blocknr;
460{
461 int tmp;
462
463 /* if the next block is actually what we thought it is,
464 then set the goal to what we thought it should be
465 */
466 if(ip->i_next_alloc_block == lbn)
467 return ip->i_next_alloc_goal;
468
469 /* now check whether we were provided with an array that basically
470 tells us previous blocks to which we want to stay closeby
471 */
472 if(bap)
473 for (tmp = indx - 1; tmp >= 0; tmp--)
474 if (bap[tmp])
475 return bap[tmp];
476
477 /* else let's fall back to the blocknr, or, if there is none,
478 follow the rule that a block should be allocated near its inode
479 */
480 return blocknr ? blocknr :
481 (daddr_t)(ip->i_block_group *
482 EXT2_BLOCKS_PER_GROUP(ip->i_e2fs)) +
483 ip->i_e2fs->s_es->s_first_data_block;
484}
485
486/*
487 * Free a block or fragment.
488 *
489 * pass on to the Linux code
490 */
491void
492ext2_blkfree(ip, bno, size)
493 register struct inode *ip;
494 daddr_t bno;
495 long size;
496{
497 register struct ext2_sb_info *fs;
498
499 fs = ip->i_e2fs;
500 /*
501 * call Linux code with mount *, block number, count
502 */
503 ext2_free_blocks(ITOV(ip)->v_mount, bno, size / fs->s_frag_size);
504}
505
506/*
507 * Free an inode.
508 *
509 * the maintenance of the actual bitmaps is again up to the linux code
510 */
511int
512ext2_vfree(pvp, ino, mode)
513 struct vnode *pvp;
514 ino_t ino;
515 int mode;
516{
517 register struct ext2_sb_info *fs;
518 register struct inode *pip;
519 register mode_t save_i_mode;
520
521 pip = VTOI(pvp);
522 fs = pip->i_e2fs;
523 if ((u_int)ino >= fs->s_inodes_per_group * fs->s_groups_count)
524 panic("ext2_vfree: range: dev = (%d, %d), ino = %d, fs = %s",
525 major(pip->i_dev), minor(pip->i_dev), ino, fs->fs_fsmnt);
526
527/* ext2_debug("ext2_vfree (%d, %d) called\n", pip->i_number, mode);
528 */
529 ext2_discard_prealloc(pip);
530
531 /* we need to make sure that ext2_free_inode can adjust the
532 used_dir_counts in the group summary information - I'd
533 really like to know what the rationale behind this
534 'set i_mode to zero to denote an unused inode' is
535 */
536 save_i_mode = pip->i_mode;
537 pip->i_mode = mode;
538 ext2_free_inode(pip);
539 pip->i_mode = save_i_mode;
540 return (0);
541}
542
543/*
544 * Fserr prints the name of a file system with an error diagnostic.
545 *
546 * The form of the error message is:
547 * fs: error message
548 */
549static void
550ext2_fserr(fs, uid, cp)
551 struct ext2_sb_info *fs;
552 u_int uid;
553 char *cp;
554{
555
556 log(LOG_ERR, "uid %d on %s: %s\n", uid, fs->fs_fsmnt, cp);
557}
202 * physical block numbers in the buffer pointers and in the inode are
203 * changed to reflect the new allocation. If unsuccessful, the allocation
204 * is left unchanged. The success in doing the reallocation is returned.
205 * Note that the error return is not reflected back to the user. Rather
206 * the previous block allocation will be used.
207 */
208
209#ifdef FANCY_REALLOC
210#include <sys/sysctl.h>
211static int doasyncfree = 1;
212#ifdef OPT_DEBUG
213SYSCTL_INT(_debug, 14, doasyncfree, CTLFLAG_RW, &doasyncfree, 0, "");
214#endif /* OPT_DEBUG */
215#endif
216
217int
218ext2_reallocblks(ap)
219 struct vop_reallocblks_args /* {
220 struct vnode *a_vp;
221 struct cluster_save *a_buflist;
222 } */ *ap;
223{
224#ifndef FANCY_REALLOC
225/* printf("ext2_reallocblks not implemented\n"); */
226return ENOSPC;
227#else
228
229 struct ext2_sb_info *fs;
230 struct inode *ip;
231 struct vnode *vp;
232 struct buf *sbp, *ebp;
233 daddr_t *bap, *sbap, *ebap;
234 struct cluster_save *buflist;
235 daddr_t start_lbn, end_lbn, soff, eoff, newblk, blkno;
236 struct indir start_ap[NIADDR + 1], end_ap[NIADDR + 1], *idp;
237 int i, len, start_lvl, end_lvl, pref, ssize;
238
239 vp = ap->a_vp;
240 ip = VTOI(vp);
241 fs = ip->i_e2fs;
242#ifdef UNKLAR
243 if (fs->fs_contigsumsize <= 0)
244 return (ENOSPC);
245#endif
246 buflist = ap->a_buflist;
247 len = buflist->bs_nchildren;
248 start_lbn = buflist->bs_children[0]->b_lblkno;
249 end_lbn = start_lbn + len - 1;
250#if DIAGNOSTIC
251 for (i = 1; i < len; i++)
252 if (buflist->bs_children[i]->b_lblkno != start_lbn + i)
253 panic("ext2_reallocblks: non-cluster");
254#endif
255 /*
256 * If the latest allocation is in a new cylinder group, assume that
257 * the filesystem has decided to move and do not force it back to
258 * the previous cylinder group.
259 */
260 if (dtog(fs, dbtofsb(fs, buflist->bs_children[0]->b_blkno)) !=
261 dtog(fs, dbtofsb(fs, buflist->bs_children[len - 1]->b_blkno)))
262 return (ENOSPC);
263 if (ufs_getlbns(vp, start_lbn, start_ap, &start_lvl) ||
264 ufs_getlbns(vp, end_lbn, end_ap, &end_lvl))
265 return (ENOSPC);
266 /*
267 * Get the starting offset and block map for the first block.
268 */
269 if (start_lvl == 0) {
270 sbap = &ip->i_db[0];
271 soff = start_lbn;
272 } else {
273 idp = &start_ap[start_lvl - 1];
274 if (bread(vp, idp->in_lbn, (int)fs->s_blocksize, NOCRED, &sbp)) {
275 brelse(sbp);
276 return (ENOSPC);
277 }
278 sbap = (daddr_t *)sbp->b_data;
279 soff = idp->in_off;
280 }
281 /*
282 * Find the preferred location for the cluster.
283 */
284 pref = ext2_blkpref(ip, start_lbn, soff, sbap);
285 /*
286 * If the block range spans two block maps, get the second map.
287 */
288 if (end_lvl == 0 || (idp = &end_ap[end_lvl - 1])->in_off + 1 >= len) {
289 ssize = len;
290 } else {
291#if DIAGNOSTIC
292 if (start_ap[start_lvl-1].in_lbn == idp->in_lbn)
293 panic("ext2_reallocblk: start == end");
294#endif
295 ssize = len - (idp->in_off + 1);
296 if (bread(vp, idp->in_lbn, (int)fs->s_blocksize, NOCRED, &ebp))
297 goto fail;
298 ebap = (daddr_t *)ebp->b_data;
299 }
300 /*
301 * Search the block map looking for an allocation of the desired size.
302 */
303 if ((newblk = (daddr_t)ext2_hashalloc(ip, dtog(fs, pref), (long)pref,
304 len, (u_long (*)())ext2_clusteralloc)) == 0)
305 goto fail;
306 /*
307 * We have found a new contiguous block.
308 *
309 * First we have to replace the old block pointers with the new
310 * block pointers in the inode and indirect blocks associated
311 * with the file.
312 */
313 blkno = newblk;
314 for (bap = &sbap[soff], i = 0; i < len; i++, blkno += fs->s_frags_per_block) {
315 if (i == ssize)
316 bap = ebap;
317#if DIAGNOSTIC
318 if (buflist->bs_children[i]->b_blkno != fsbtodb(fs, *bap))
319 panic("ext2_reallocblks: alloc mismatch");
320#endif
321 *bap++ = blkno;
322 }
323 /*
324 * Next we must write out the modified inode and indirect blocks.
325 * For strict correctness, the writes should be synchronous since
326 * the old block values may have been written to disk. In practise
327 * they are almost never written, but if we are concerned about
328 * strict correctness, the `doasyncfree' flag should be set to zero.
329 *
330 * The test on `doasyncfree' should be changed to test a flag
331 * that shows whether the associated buffers and inodes have
332 * been written. The flag should be set when the cluster is
333 * started and cleared whenever the buffer or inode is flushed.
334 * We can then check below to see if it is set, and do the
335 * synchronous write only when it has been cleared.
336 */
337 if (sbap != &ip->i_db[0]) {
338 if (doasyncfree)
339 bdwrite(sbp);
340 else
341 bwrite(sbp);
342 } else {
343 ip->i_flag |= IN_CHANGE | IN_UPDATE;
344 if (!doasyncfree)
345 UFS_UPDATE(vp, 1);
346 }
347 if (ssize < len)
348 if (doasyncfree)
349 bdwrite(ebp);
350 else
351 bwrite(ebp);
352 /*
353 * Last, free the old blocks and assign the new blocks to the buffers.
354 */
355 for (blkno = newblk, i = 0; i < len; i++, blkno += fs->s_frags_per_block) {
356 ext2_blkfree(ip, dbtofsb(fs, buflist->bs_children[i]->b_blkno),
357 fs->s_blocksize);
358 buflist->bs_children[i]->b_blkno = fsbtodb(fs, blkno);
359 }
360 return (0);
361
362fail:
363 if (ssize < len)
364 brelse(ebp);
365 if (sbap != &ip->i_db[0])
366 brelse(sbp);
367 return (ENOSPC);
368
369#endif /* FANCY_REALLOC */
370}
371
372/*
373 * Allocate an inode in the file system.
374 *
375 * we leave the actual allocation strategy to the (modified)
376 * ext2_new_inode(), to make sure we get the policies right
377 */
378int
379ext2_valloc(pvp, mode, cred, vpp)
380 struct vnode *pvp;
381 int mode;
382 struct ucred *cred;
383 struct vnode **vpp;
384{
385 register struct inode *pip;
386 register struct ext2_sb_info *fs;
387 register struct inode *ip;
388 ino_t ino;
389 int i, error;
390
391 *vpp = NULL;
392 pip = VTOI(pvp);
393 fs = pip->i_e2fs;
394 if (fs->s_es->s_free_inodes_count == 0)
395 goto noinodes;
396
397 /* call the Linux routine - it returns the inode number only */
398 ino = ext2_new_inode(pip, mode);
399
400 if (ino == 0)
401 goto noinodes;
402 error = VFS_VGET(pvp->v_mount, ino, vpp);
403 if (error) {
404 UFS_VFREE(pvp, ino, mode);
405 return (error);
406 }
407 ip = VTOI(*vpp);
408
409 /*
410 the question is whether using VGET was such good idea at all -
411 Linux doesn't read the old inode in when it's allocating a
412 new one. I will set at least i_size & i_blocks the zero.
413 */
414 ip->i_mode = 0;
415 ip->i_size = 0;
416 ip->i_blocks = 0;
417 ip->i_flags = 0;
418 /* now we want to make sure that the block pointers are zeroed out */
419 for (i = 0; i < NDADDR; i++)
420 ip->i_db[i] = 0;
421 for (i = 0; i < NIADDR; i++)
422 ip->i_ib[i] = 0;
423
424 /*
425 * Set up a new generation number for this inode.
426 * XXX check if this makes sense in ext2
427 */
428 if (ip->i_gen == 0 || ++ip->i_gen == 0)
429 ip->i_gen = random() / 2 + 1;
430/*
431printf("ext2_valloc: allocated inode %d\n", ino);
432*/
433 return (0);
434noinodes:
435 ext2_fserr(fs, cred->cr_uid, "out of inodes");
436 uprintf("\n%s: create/symlink failed, no inodes free\n", fs->fs_fsmnt);
437 return (ENOSPC);
438}
439
440/*
441 * Select the desired position for the next block in a file.
442 *
443 * we try to mimic what Remy does in inode_getblk/block_getblk
444 *
445 * we note: blocknr == 0 means that we're about to allocate either
446 * a direct block or a pointer block at the first level of indirection
447 * (In other words, stuff that will go in i_db[] or i_ib[])
448 *
449 * blocknr != 0 means that we're allocating a block that is none
450 * of the above. Then, blocknr tells us the number of the block
451 * that will hold the pointer
452 */
453daddr_t
454ext2_blkpref(ip, lbn, indx, bap, blocknr)
455 struct inode *ip;
456 daddr_t lbn;
457 int indx;
458 daddr_t *bap;
459 daddr_t blocknr;
460{
461 int tmp;
462
463 /* if the next block is actually what we thought it is,
464 then set the goal to what we thought it should be
465 */
466 if(ip->i_next_alloc_block == lbn)
467 return ip->i_next_alloc_goal;
468
469 /* now check whether we were provided with an array that basically
470 tells us previous blocks to which we want to stay closeby
471 */
472 if(bap)
473 for (tmp = indx - 1; tmp >= 0; tmp--)
474 if (bap[tmp])
475 return bap[tmp];
476
477 /* else let's fall back to the blocknr, or, if there is none,
478 follow the rule that a block should be allocated near its inode
479 */
480 return blocknr ? blocknr :
481 (daddr_t)(ip->i_block_group *
482 EXT2_BLOCKS_PER_GROUP(ip->i_e2fs)) +
483 ip->i_e2fs->s_es->s_first_data_block;
484}
485
486/*
487 * Free a block or fragment.
488 *
489 * pass on to the Linux code
490 */
491void
492ext2_blkfree(ip, bno, size)
493 register struct inode *ip;
494 daddr_t bno;
495 long size;
496{
497 register struct ext2_sb_info *fs;
498
499 fs = ip->i_e2fs;
500 /*
501 * call Linux code with mount *, block number, count
502 */
503 ext2_free_blocks(ITOV(ip)->v_mount, bno, size / fs->s_frag_size);
504}
505
506/*
507 * Free an inode.
508 *
509 * the maintenance of the actual bitmaps is again up to the linux code
510 */
511int
512ext2_vfree(pvp, ino, mode)
513 struct vnode *pvp;
514 ino_t ino;
515 int mode;
516{
517 register struct ext2_sb_info *fs;
518 register struct inode *pip;
519 register mode_t save_i_mode;
520
521 pip = VTOI(pvp);
522 fs = pip->i_e2fs;
523 if ((u_int)ino >= fs->s_inodes_per_group * fs->s_groups_count)
524 panic("ext2_vfree: range: dev = (%d, %d), ino = %d, fs = %s",
525 major(pip->i_dev), minor(pip->i_dev), ino, fs->fs_fsmnt);
526
527/* ext2_debug("ext2_vfree (%d, %d) called\n", pip->i_number, mode);
528 */
529 ext2_discard_prealloc(pip);
530
531 /* we need to make sure that ext2_free_inode can adjust the
532 used_dir_counts in the group summary information - I'd
533 really like to know what the rationale behind this
534 'set i_mode to zero to denote an unused inode' is
535 */
536 save_i_mode = pip->i_mode;
537 pip->i_mode = mode;
538 ext2_free_inode(pip);
539 pip->i_mode = save_i_mode;
540 return (0);
541}
542
543/*
544 * Fserr prints the name of a file system with an error diagnostic.
545 *
546 * The form of the error message is:
547 * fs: error message
548 */
549static void
550ext2_fserr(fs, uid, cp)
551 struct ext2_sb_info *fs;
552 u_int uid;
553 char *cp;
554{
555
556 log(LOG_ERR, "uid %d on %s: %s\n", uid, fs->fs_fsmnt, cp);
557}