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