1*0a6a1f1dSLionel Sambuc /* $NetBSD: lfs_alloc.c,v 1.130 2015/09/13 07:53:37 dholland Exp $ */
2d65f6f70SBen Gras
3d65f6f70SBen Gras /*-
4d65f6f70SBen Gras * Copyright (c) 1999, 2000, 2001, 2002, 2003, 2007 The NetBSD Foundation, Inc.
5d65f6f70SBen Gras * All rights reserved.
6d65f6f70SBen Gras *
7d65f6f70SBen Gras * This code is derived from software contributed to The NetBSD Foundation
8d65f6f70SBen Gras * by Konrad E. Schroder <perseant@hhhh.org>.
9d65f6f70SBen Gras *
10d65f6f70SBen Gras * Redistribution and use in source and binary forms, with or without
11d65f6f70SBen Gras * modification, are permitted provided that the following conditions
12d65f6f70SBen Gras * are met:
13d65f6f70SBen Gras * 1. Redistributions of source code must retain the above copyright
14d65f6f70SBen Gras * notice, this list of conditions and the following disclaimer.
15d65f6f70SBen Gras * 2. Redistributions in binary form must reproduce the above copyright
16d65f6f70SBen Gras * notice, this list of conditions and the following disclaimer in the
17d65f6f70SBen Gras * documentation and/or other materials provided with the distribution.
18d65f6f70SBen Gras *
19d65f6f70SBen Gras * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20d65f6f70SBen Gras * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21d65f6f70SBen Gras * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22d65f6f70SBen Gras * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23d65f6f70SBen Gras * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24d65f6f70SBen Gras * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25d65f6f70SBen Gras * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26d65f6f70SBen Gras * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27d65f6f70SBen Gras * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28d65f6f70SBen Gras * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29d65f6f70SBen Gras * POSSIBILITY OF SUCH DAMAGE.
30d65f6f70SBen Gras */
31d65f6f70SBen Gras /*
32d65f6f70SBen Gras * Copyright (c) 1991, 1993
33d65f6f70SBen Gras * The Regents of the University of California. All rights reserved.
34d65f6f70SBen Gras *
35d65f6f70SBen Gras * Redistribution and use in source and binary forms, with or without
36d65f6f70SBen Gras * modification, are permitted provided that the following conditions
37d65f6f70SBen Gras * are met:
38d65f6f70SBen Gras * 1. Redistributions of source code must retain the above copyright
39d65f6f70SBen Gras * notice, this list of conditions and the following disclaimer.
40d65f6f70SBen Gras * 2. Redistributions in binary form must reproduce the above copyright
41d65f6f70SBen Gras * notice, this list of conditions and the following disclaimer in the
42d65f6f70SBen Gras * documentation and/or other materials provided with the distribution.
43d65f6f70SBen Gras * 3. Neither the name of the University nor the names of its contributors
44d65f6f70SBen Gras * may be used to endorse or promote products derived from this software
45d65f6f70SBen Gras * without specific prior written permission.
46d65f6f70SBen Gras *
47d65f6f70SBen Gras * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48d65f6f70SBen Gras * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49d65f6f70SBen Gras * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50d65f6f70SBen Gras * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51d65f6f70SBen Gras * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52d65f6f70SBen Gras * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53d65f6f70SBen Gras * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54d65f6f70SBen Gras * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55d65f6f70SBen Gras * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56d65f6f70SBen Gras * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57d65f6f70SBen Gras * SUCH DAMAGE.
58d65f6f70SBen Gras *
59d65f6f70SBen Gras * @(#)lfs_alloc.c 8.4 (Berkeley) 1/4/94
60d65f6f70SBen Gras */
61d65f6f70SBen Gras
62d65f6f70SBen Gras #include <sys/cdefs.h>
63*0a6a1f1dSLionel Sambuc __KERNEL_RCSID(0, "$NetBSD: lfs_alloc.c,v 1.130 2015/09/13 07:53:37 dholland Exp $");
64d65f6f70SBen Gras
65d65f6f70SBen Gras #if defined(_KERNEL_OPT)
66d65f6f70SBen Gras #include "opt_quota.h"
67d65f6f70SBen Gras #endif
68d65f6f70SBen Gras
69d65f6f70SBen Gras #include <sys/param.h>
70d65f6f70SBen Gras #include <sys/systm.h>
71d65f6f70SBen Gras #include <sys/kernel.h>
72d65f6f70SBen Gras #include <sys/buf.h>
73d65f6f70SBen Gras #include <sys/lock.h>
74d65f6f70SBen Gras #include <sys/vnode.h>
75d65f6f70SBen Gras #include <sys/syslog.h>
76d65f6f70SBen Gras #include <sys/mount.h>
77d65f6f70SBen Gras #include <sys/malloc.h>
78d65f6f70SBen Gras #include <sys/pool.h>
79d65f6f70SBen Gras #include <sys/proc.h>
80d65f6f70SBen Gras #include <sys/tree.h>
81d65f6f70SBen Gras #include <sys/kauth.h>
82d65f6f70SBen Gras
8384d9c625SLionel Sambuc #include <ufs/lfs/ulfs_quotacommon.h>
8484d9c625SLionel Sambuc #include <ufs/lfs/ulfs_inode.h>
8584d9c625SLionel Sambuc #include <ufs/lfs/ulfsmount.h>
8684d9c625SLionel Sambuc #include <ufs/lfs/ulfs_extern.h>
87d65f6f70SBen Gras
88d65f6f70SBen Gras #include <ufs/lfs/lfs.h>
89*0a6a1f1dSLionel Sambuc #include <ufs/lfs/lfs_accessors.h>
90d65f6f70SBen Gras #include <ufs/lfs/lfs_extern.h>
9184d9c625SLionel Sambuc #include <ufs/lfs/lfs_kernel.h>
92d65f6f70SBen Gras
93d65f6f70SBen Gras /* Constants for inode free bitmap */
94d65f6f70SBen Gras #define BMSHIFT 5 /* 2 ** 5 = 32 */
95d65f6f70SBen Gras #define BMMASK ((1 << BMSHIFT) - 1)
96d65f6f70SBen Gras #define SET_BITMAP_FREE(F, I) do { \
97d65f6f70SBen Gras DLOG((DLOG_ALLOC, "lfs: ino %d wrd %d bit %d set\n", (int)(I), \
98d65f6f70SBen Gras (int)((I) >> BMSHIFT), (int)((I) & BMMASK))); \
99d65f6f70SBen Gras (F)->lfs_ino_bitmap[(I) >> BMSHIFT] |= (1 << ((I) & BMMASK)); \
100d65f6f70SBen Gras } while (0)
101d65f6f70SBen Gras #define CLR_BITMAP_FREE(F, I) do { \
102d65f6f70SBen Gras DLOG((DLOG_ALLOC, "lfs: ino %d wrd %d bit %d clr\n", (int)(I), \
103d65f6f70SBen Gras (int)((I) >> BMSHIFT), (int)((I) & BMMASK))); \
104d65f6f70SBen Gras (F)->lfs_ino_bitmap[(I) >> BMSHIFT] &= ~(1 << ((I) & BMMASK)); \
105d65f6f70SBen Gras } while(0)
106d65f6f70SBen Gras
107d65f6f70SBen Gras #define ISSET_BITMAP_FREE(F, I) \
108d65f6f70SBen Gras ((F)->lfs_ino_bitmap[(I) >> BMSHIFT] & (1 << ((I) & BMMASK)))
109d65f6f70SBen Gras
110d65f6f70SBen Gras /*
111d65f6f70SBen Gras * Add a new block to the Ifile, to accommodate future file creations.
112d65f6f70SBen Gras * Called with the segment lock held.
113d65f6f70SBen Gras */
114d65f6f70SBen Gras int
lfs_extend_ifile(struct lfs * fs,kauth_cred_t cred)115d65f6f70SBen Gras lfs_extend_ifile(struct lfs *fs, kauth_cred_t cred)
116d65f6f70SBen Gras {
117d65f6f70SBen Gras struct vnode *vp;
118d65f6f70SBen Gras struct inode *ip;
119*0a6a1f1dSLionel Sambuc IFILE64 *ifp64;
120*0a6a1f1dSLionel Sambuc IFILE32 *ifp32;
121d65f6f70SBen Gras IFILE_V1 *ifp_v1;
122d65f6f70SBen Gras struct buf *bp, *cbp;
123d65f6f70SBen Gras int error;
124d65f6f70SBen Gras daddr_t i, blkno, xmax;
125d65f6f70SBen Gras ino_t oldlast, maxino;
126d65f6f70SBen Gras CLEANERINFO *cip;
127d65f6f70SBen Gras
128d65f6f70SBen Gras ASSERT_SEGLOCK(fs);
129d65f6f70SBen Gras
130d65f6f70SBen Gras vp = fs->lfs_ivnode;
131d65f6f70SBen Gras ip = VTOI(vp);
13284d9c625SLionel Sambuc blkno = lfs_lblkno(fs, ip->i_size);
133*0a6a1f1dSLionel Sambuc if ((error = lfs_balloc(vp, ip->i_size, lfs_sb_getbsize(fs), cred, 0,
134d65f6f70SBen Gras &bp)) != 0) {
135d65f6f70SBen Gras return (error);
136d65f6f70SBen Gras }
137*0a6a1f1dSLionel Sambuc ip->i_size += lfs_sb_getbsize(fs);
138*0a6a1f1dSLionel Sambuc lfs_dino_setsize(fs, ip->i_din, ip->i_size);
139d65f6f70SBen Gras uvm_vnp_setsize(vp, ip->i_size);
140d65f6f70SBen Gras
141*0a6a1f1dSLionel Sambuc maxino = ((ip->i_size >> lfs_sb_getbshift(fs)) - lfs_sb_getcleansz(fs) -
142*0a6a1f1dSLionel Sambuc lfs_sb_getsegtabsz(fs)) * lfs_sb_getifpb(fs);
143d65f6f70SBen Gras fs->lfs_ino_bitmap = (lfs_bm_t *)
144d65f6f70SBen Gras realloc(fs->lfs_ino_bitmap, ((maxino + BMMASK) >> BMSHIFT) *
145d65f6f70SBen Gras sizeof(lfs_bm_t), M_SEGMENT, M_WAITOK);
146d65f6f70SBen Gras KASSERT(fs->lfs_ino_bitmap != NULL);
147d65f6f70SBen Gras
148*0a6a1f1dSLionel Sambuc i = (blkno - lfs_sb_getsegtabsz(fs) - lfs_sb_getcleansz(fs)) *
149*0a6a1f1dSLionel Sambuc lfs_sb_getifpb(fs);
150d65f6f70SBen Gras
151d65f6f70SBen Gras /*
152d65f6f70SBen Gras * We insert the new inodes at the head of the free list.
153d65f6f70SBen Gras * Under normal circumstances, the free list is empty here,
154d65f6f70SBen Gras * so we are also incidentally placing them at the end (which
155d65f6f70SBen Gras * we must do if we are to keep them in order).
156d65f6f70SBen Gras */
157d65f6f70SBen Gras LFS_GET_HEADFREE(fs, cip, cbp, &oldlast);
158d65f6f70SBen Gras LFS_PUT_HEADFREE(fs, cip, cbp, i);
159d65f6f70SBen Gras #ifdef DIAGNOSTIC
160*0a6a1f1dSLionel Sambuc if (lfs_sb_getfreehd(fs) == LFS_UNUSED_INUM)
161d65f6f70SBen Gras panic("inode 0 allocated [2]");
162d65f6f70SBen Gras #endif /* DIAGNOSTIC */
163*0a6a1f1dSLionel Sambuc xmax = i + lfs_sb_getifpb(fs);
164d65f6f70SBen Gras
165*0a6a1f1dSLionel Sambuc if (fs->lfs_is64) {
166*0a6a1f1dSLionel Sambuc for (ifp64 = (IFILE64 *)bp->b_data; i < xmax; ++ifp64) {
167*0a6a1f1dSLionel Sambuc SET_BITMAP_FREE(fs, i);
168*0a6a1f1dSLionel Sambuc ifp64->if_version = 1;
169*0a6a1f1dSLionel Sambuc ifp64->if_daddr = LFS_UNUSED_DADDR;
170*0a6a1f1dSLionel Sambuc ifp64->if_nextfree = ++i;
171*0a6a1f1dSLionel Sambuc }
172*0a6a1f1dSLionel Sambuc ifp64--;
173*0a6a1f1dSLionel Sambuc ifp64->if_nextfree = oldlast;
174*0a6a1f1dSLionel Sambuc } else if (lfs_sb_getversion(fs) > 1) {
175*0a6a1f1dSLionel Sambuc for (ifp32 = (IFILE32 *)bp->b_data; i < xmax; ++ifp32) {
176*0a6a1f1dSLionel Sambuc SET_BITMAP_FREE(fs, i);
177*0a6a1f1dSLionel Sambuc ifp32->if_version = 1;
178*0a6a1f1dSLionel Sambuc ifp32->if_daddr = LFS_UNUSED_DADDR;
179*0a6a1f1dSLionel Sambuc ifp32->if_nextfree = ++i;
180*0a6a1f1dSLionel Sambuc }
181*0a6a1f1dSLionel Sambuc ifp32--;
182*0a6a1f1dSLionel Sambuc ifp32->if_nextfree = oldlast;
183*0a6a1f1dSLionel Sambuc } else {
184d65f6f70SBen Gras for (ifp_v1 = (IFILE_V1 *)bp->b_data; i < xmax; ++ifp_v1) {
185d65f6f70SBen Gras SET_BITMAP_FREE(fs, i);
186d65f6f70SBen Gras ifp_v1->if_version = 1;
187d65f6f70SBen Gras ifp_v1->if_daddr = LFS_UNUSED_DADDR;
188d65f6f70SBen Gras ifp_v1->if_nextfree = ++i;
189d65f6f70SBen Gras }
190d65f6f70SBen Gras ifp_v1--;
191d65f6f70SBen Gras ifp_v1->if_nextfree = oldlast;
192d65f6f70SBen Gras }
193d65f6f70SBen Gras LFS_PUT_TAILFREE(fs, cip, cbp, xmax - 1);
194d65f6f70SBen Gras
195d65f6f70SBen Gras (void) LFS_BWRITE_LOG(bp); /* Ifile */
196d65f6f70SBen Gras
197d65f6f70SBen Gras return 0;
198d65f6f70SBen Gras }
199d65f6f70SBen Gras
200d65f6f70SBen Gras /* Allocate a new inode. */
201d65f6f70SBen Gras /* ARGSUSED */
202d65f6f70SBen Gras /* VOP_BWRITE 2i times */
203d65f6f70SBen Gras int
lfs_valloc(struct vnode * pvp,int mode,kauth_cred_t cred,ino_t * ino,int * gen)204d65f6f70SBen Gras lfs_valloc(struct vnode *pvp, int mode, kauth_cred_t cred,
205*0a6a1f1dSLionel Sambuc ino_t *ino, int *gen)
206d65f6f70SBen Gras {
207d65f6f70SBen Gras struct lfs *fs;
208d65f6f70SBen Gras struct buf *bp, *cbp;
209*0a6a1f1dSLionel Sambuc IFILE *ifp;
210d65f6f70SBen Gras int error;
211d65f6f70SBen Gras CLEANERINFO *cip;
212d65f6f70SBen Gras
213d65f6f70SBen Gras fs = VTOI(pvp)->i_lfs;
214d65f6f70SBen Gras if (fs->lfs_ronly)
215d65f6f70SBen Gras return EROFS;
216d65f6f70SBen Gras
217d65f6f70SBen Gras ASSERT_NO_SEGLOCK(fs);
218d65f6f70SBen Gras
219d65f6f70SBen Gras lfs_seglock(fs, SEGM_PROT);
220d65f6f70SBen Gras
221d65f6f70SBen Gras /* Get the head of the freelist. */
222*0a6a1f1dSLionel Sambuc LFS_GET_HEADFREE(fs, cip, cbp, ino);
223*0a6a1f1dSLionel Sambuc KASSERT(*ino != LFS_UNUSED_INUM && *ino != LFS_IFILE_INUM);
224d65f6f70SBen Gras
225*0a6a1f1dSLionel Sambuc DLOG((DLOG_ALLOC, "lfs_valloc: allocate inode %" PRId64 "\n",
226*0a6a1f1dSLionel Sambuc *ino));
227d65f6f70SBen Gras
228d65f6f70SBen Gras /*
229d65f6f70SBen Gras * Remove the inode from the free list and write the new start
230d65f6f70SBen Gras * of the free list into the superblock.
231d65f6f70SBen Gras */
232*0a6a1f1dSLionel Sambuc CLR_BITMAP_FREE(fs, *ino);
233*0a6a1f1dSLionel Sambuc LFS_IENTRY(ifp, fs, *ino, bp);
234*0a6a1f1dSLionel Sambuc if (lfs_if_getdaddr(fs, ifp) != LFS_UNUSED_DADDR)
235*0a6a1f1dSLionel Sambuc panic("lfs_valloc: inuse inode %" PRId64 " on the free list",
236*0a6a1f1dSLionel Sambuc *ino);
237*0a6a1f1dSLionel Sambuc LFS_PUT_HEADFREE(fs, cip, cbp, lfs_if_getnextfree(fs, ifp));
238*0a6a1f1dSLionel Sambuc DLOG((DLOG_ALLOC, "lfs_valloc: headfree %" PRId64 " -> %ju\n",
239*0a6a1f1dSLionel Sambuc *ino, (uintmax_t)lfs_if_getnextfree(fs, ifp)));
240d65f6f70SBen Gras
241*0a6a1f1dSLionel Sambuc /* version was updated by vfree */
242*0a6a1f1dSLionel Sambuc *gen = lfs_if_getversion(fs, ifp);
243d65f6f70SBen Gras brelse(bp, 0);
244d65f6f70SBen Gras
245d65f6f70SBen Gras /* Extend IFILE so that the next lfs_valloc will succeed. */
246*0a6a1f1dSLionel Sambuc if (lfs_sb_getfreehd(fs) == LFS_UNUSED_INUM) {
247d65f6f70SBen Gras if ((error = lfs_extend_ifile(fs, cred)) != 0) {
248*0a6a1f1dSLionel Sambuc LFS_PUT_HEADFREE(fs, cip, cbp, *ino);
249d65f6f70SBen Gras lfs_segunlock(fs);
250d65f6f70SBen Gras return error;
251d65f6f70SBen Gras }
252d65f6f70SBen Gras }
253d65f6f70SBen Gras #ifdef DIAGNOSTIC
254*0a6a1f1dSLionel Sambuc if (lfs_sb_getfreehd(fs) == LFS_UNUSED_INUM)
255d65f6f70SBen Gras panic("inode 0 allocated [3]");
256d65f6f70SBen Gras #endif /* DIAGNOSTIC */
257d65f6f70SBen Gras
258d65f6f70SBen Gras /* Set superblock modified bit and increment file count. */
259d65f6f70SBen Gras mutex_enter(&lfs_lock);
260d65f6f70SBen Gras fs->lfs_fmod = 1;
261d65f6f70SBen Gras mutex_exit(&lfs_lock);
262*0a6a1f1dSLionel Sambuc lfs_sb_addnfiles(fs, 1);
263d65f6f70SBen Gras
264d65f6f70SBen Gras lfs_segunlock(fs);
265d65f6f70SBen Gras
266*0a6a1f1dSLionel Sambuc return 0;
267d65f6f70SBen Gras }
268d65f6f70SBen Gras
269d65f6f70SBen Gras /*
270*0a6a1f1dSLionel Sambuc * Allocate a new inode with given inode number and version.
271d65f6f70SBen Gras */
272d65f6f70SBen Gras int
lfs_valloc_fixed(struct lfs * fs,ino_t ino,int vers)273*0a6a1f1dSLionel Sambuc lfs_valloc_fixed(struct lfs *fs, ino_t ino, int vers)
274d65f6f70SBen Gras {
275*0a6a1f1dSLionel Sambuc IFILE *ifp;
276*0a6a1f1dSLionel Sambuc struct buf *bp, *cbp;
277*0a6a1f1dSLionel Sambuc ino_t headino, thisino, oldnext;
278*0a6a1f1dSLionel Sambuc CLEANERINFO *cip;
279d65f6f70SBen Gras
280*0a6a1f1dSLionel Sambuc /* If the Ifile is too short to contain this inum, extend it */
281*0a6a1f1dSLionel Sambuc while (VTOI(fs->lfs_ivnode)->i_size <= (ino /
282*0a6a1f1dSLionel Sambuc lfs_sb_getifpb(fs) + lfs_sb_getcleansz(fs) + lfs_sb_getsegtabsz(fs))
283*0a6a1f1dSLionel Sambuc << lfs_sb_getbshift(fs)) {
284*0a6a1f1dSLionel Sambuc lfs_extend_ifile(fs, NOCRED);
285d65f6f70SBen Gras }
286d65f6f70SBen Gras
287*0a6a1f1dSLionel Sambuc LFS_IENTRY(ifp, fs, ino, bp);
288*0a6a1f1dSLionel Sambuc oldnext = lfs_if_getnextfree(fs, ifp);
289*0a6a1f1dSLionel Sambuc lfs_if_setversion(fs, ifp, vers);
290*0a6a1f1dSLionel Sambuc brelse(bp, 0);
291d65f6f70SBen Gras
292*0a6a1f1dSLionel Sambuc LFS_GET_HEADFREE(fs, cip, cbp, &headino);
293*0a6a1f1dSLionel Sambuc if (headino == ino) {
294*0a6a1f1dSLionel Sambuc LFS_PUT_HEADFREE(fs, cip, cbp, oldnext);
295*0a6a1f1dSLionel Sambuc } else {
296*0a6a1f1dSLionel Sambuc ino_t nextfree;
297d65f6f70SBen Gras
298*0a6a1f1dSLionel Sambuc thisino = headino;
299*0a6a1f1dSLionel Sambuc while (1) {
300*0a6a1f1dSLionel Sambuc LFS_IENTRY(ifp, fs, thisino, bp);
301*0a6a1f1dSLionel Sambuc nextfree = lfs_if_getnextfree(fs, ifp);
302*0a6a1f1dSLionel Sambuc if (nextfree == ino ||
303*0a6a1f1dSLionel Sambuc nextfree == LFS_UNUSED_INUM)
304*0a6a1f1dSLionel Sambuc break;
305*0a6a1f1dSLionel Sambuc thisino = nextfree;
306*0a6a1f1dSLionel Sambuc brelse(bp, 0);
307*0a6a1f1dSLionel Sambuc }
308*0a6a1f1dSLionel Sambuc if (nextfree == LFS_UNUSED_INUM) {
309*0a6a1f1dSLionel Sambuc brelse(bp, 0);
310*0a6a1f1dSLionel Sambuc return ENOENT;
311*0a6a1f1dSLionel Sambuc }
312*0a6a1f1dSLionel Sambuc lfs_if_setnextfree(fs, ifp, oldnext);
313*0a6a1f1dSLionel Sambuc LFS_BWRITE_LOG(bp);
314d65f6f70SBen Gras }
315d65f6f70SBen Gras
316*0a6a1f1dSLionel Sambuc return 0;
317d65f6f70SBen Gras }
318d65f6f70SBen Gras
319d65f6f70SBen Gras #if 0
320d65f6f70SBen Gras /*
321d65f6f70SBen Gras * Find the highest-numbered allocated inode.
322d65f6f70SBen Gras * This will be used to shrink the Ifile.
323d65f6f70SBen Gras */
324d65f6f70SBen Gras static inline ino_t
325d65f6f70SBen Gras lfs_last_alloc_ino(struct lfs *fs)
326d65f6f70SBen Gras {
327d65f6f70SBen Gras ino_t ino, maxino;
328d65f6f70SBen Gras
329*0a6a1f1dSLionel Sambuc maxino = ((fs->lfs_ivnode->v_size >> lfs_sb_getbshift(fs)) -
330*0a6a1f1dSLionel Sambuc lfs_sb_getcleansz(fs) - lfs_sb_getsegtabsz(fs)) * fs->lfs_ifpb;
331d65f6f70SBen Gras for (ino = maxino - 1; ino > LFS_UNUSED_INUM; --ino) {
332d65f6f70SBen Gras if (ISSET_BITMAP_FREE(fs, ino) == 0)
333d65f6f70SBen Gras break;
334d65f6f70SBen Gras }
335d65f6f70SBen Gras return ino;
336d65f6f70SBen Gras }
337d65f6f70SBen Gras #endif
338d65f6f70SBen Gras
339d65f6f70SBen Gras /*
340d65f6f70SBen Gras * Find the previous (next lowest numbered) free inode, if any.
341d65f6f70SBen Gras * If there is none, return LFS_UNUSED_INUM.
342d65f6f70SBen Gras */
343d65f6f70SBen Gras static inline ino_t
lfs_freelist_prev(struct lfs * fs,ino_t ino)344d65f6f70SBen Gras lfs_freelist_prev(struct lfs *fs, ino_t ino)
345d65f6f70SBen Gras {
346d65f6f70SBen Gras ino_t tino, bound, bb, freehdbb;
347d65f6f70SBen Gras
348*0a6a1f1dSLionel Sambuc if (lfs_sb_getfreehd(fs) == LFS_UNUSED_INUM) /* No free inodes at all */
349d65f6f70SBen Gras return LFS_UNUSED_INUM;
350d65f6f70SBen Gras
351d65f6f70SBen Gras /* Search our own word first */
352d65f6f70SBen Gras bound = ino & ~BMMASK;
353d65f6f70SBen Gras for (tino = ino - 1; tino >= bound && tino > LFS_UNUSED_INUM; tino--)
354d65f6f70SBen Gras if (ISSET_BITMAP_FREE(fs, tino))
355d65f6f70SBen Gras return tino;
356d65f6f70SBen Gras /* If there are no lower words to search, just return */
357d65f6f70SBen Gras if (ino >> BMSHIFT == 0)
358d65f6f70SBen Gras return LFS_UNUSED_INUM;
359d65f6f70SBen Gras
360d65f6f70SBen Gras /*
361d65f6f70SBen Gras * Find a word with a free inode in it. We have to be a bit
362d65f6f70SBen Gras * careful here since ino_t is unsigned.
363d65f6f70SBen Gras */
364*0a6a1f1dSLionel Sambuc freehdbb = (lfs_sb_getfreehd(fs) >> BMSHIFT);
365d65f6f70SBen Gras for (bb = (ino >> BMSHIFT) - 1; bb >= freehdbb && bb > 0; --bb)
366d65f6f70SBen Gras if (fs->lfs_ino_bitmap[bb])
367d65f6f70SBen Gras break;
368d65f6f70SBen Gras if (fs->lfs_ino_bitmap[bb] == 0)
369d65f6f70SBen Gras return LFS_UNUSED_INUM;
370d65f6f70SBen Gras
371d65f6f70SBen Gras /* Search the word we found */
372d65f6f70SBen Gras for (tino = (bb << BMSHIFT) | BMMASK; tino >= (bb << BMSHIFT) &&
373d65f6f70SBen Gras tino > LFS_UNUSED_INUM; tino--)
374d65f6f70SBen Gras if (ISSET_BITMAP_FREE(fs, tino))
375d65f6f70SBen Gras break;
376d65f6f70SBen Gras
377d65f6f70SBen Gras if (tino <= LFS_IFILE_INUM)
378d65f6f70SBen Gras tino = LFS_UNUSED_INUM;
379d65f6f70SBen Gras
380d65f6f70SBen Gras return tino;
381d65f6f70SBen Gras }
382d65f6f70SBen Gras
383d65f6f70SBen Gras /* Free an inode. */
384d65f6f70SBen Gras /* ARGUSED */
385d65f6f70SBen Gras /* VOP_BWRITE 2i times */
386d65f6f70SBen Gras int
lfs_vfree(struct vnode * vp,ino_t ino,int mode)387d65f6f70SBen Gras lfs_vfree(struct vnode *vp, ino_t ino, int mode)
388d65f6f70SBen Gras {
389d65f6f70SBen Gras SEGUSE *sup;
390d65f6f70SBen Gras CLEANERINFO *cip;
391d65f6f70SBen Gras struct buf *cbp, *bp;
392*0a6a1f1dSLionel Sambuc IFILE *ifp;
393d65f6f70SBen Gras struct inode *ip;
394d65f6f70SBen Gras struct lfs *fs;
395d65f6f70SBen Gras daddr_t old_iaddr;
396d65f6f70SBen Gras ino_t otail;
397d65f6f70SBen Gras
398d65f6f70SBen Gras /* Get the inode number and file system. */
399d65f6f70SBen Gras ip = VTOI(vp);
400d65f6f70SBen Gras fs = ip->i_lfs;
401d65f6f70SBen Gras ino = ip->i_number;
402d65f6f70SBen Gras
403d65f6f70SBen Gras ASSERT_NO_SEGLOCK(fs);
404d65f6f70SBen Gras DLOG((DLOG_ALLOC, "lfs_vfree: free ino %lld\n", (long long)ino));
405d65f6f70SBen Gras
406d65f6f70SBen Gras /* Drain of pending writes */
407d65f6f70SBen Gras mutex_enter(vp->v_interlock);
408*0a6a1f1dSLionel Sambuc while (lfs_sb_getversion(fs) > 1 && WRITEINPROG(vp)) {
409d65f6f70SBen Gras cv_wait(&vp->v_cv, vp->v_interlock);
410d65f6f70SBen Gras }
411d65f6f70SBen Gras mutex_exit(vp->v_interlock);
412d65f6f70SBen Gras
413d65f6f70SBen Gras lfs_seglock(fs, SEGM_PROT);
414d65f6f70SBen Gras
415d65f6f70SBen Gras lfs_unmark_vnode(vp);
416d65f6f70SBen Gras mutex_enter(&lfs_lock);
417d65f6f70SBen Gras if (vp->v_uflag & VU_DIROP) {
418d65f6f70SBen Gras vp->v_uflag &= ~VU_DIROP;
419d65f6f70SBen Gras --lfs_dirvcount;
420d65f6f70SBen Gras --fs->lfs_dirvcount;
421d65f6f70SBen Gras TAILQ_REMOVE(&fs->lfs_dchainhd, ip, i_lfs_dchain);
422d65f6f70SBen Gras wakeup(&fs->lfs_dirvcount);
423d65f6f70SBen Gras wakeup(&lfs_dirvcount);
424d65f6f70SBen Gras mutex_exit(&lfs_lock);
425*0a6a1f1dSLionel Sambuc vrele(vp);
426d65f6f70SBen Gras
427d65f6f70SBen Gras /*
428d65f6f70SBen Gras * If this inode is not going to be written any more, any
429d65f6f70SBen Gras * segment accounting left over from its truncation needs
430d65f6f70SBen Gras * to occur at the end of the next dirops flush. Attach
431d65f6f70SBen Gras * them to the fs-wide list for that purpose.
432d65f6f70SBen Gras */
433d65f6f70SBen Gras if (LIST_FIRST(&ip->i_lfs_segdhd) != NULL) {
434d65f6f70SBen Gras struct segdelta *sd;
435d65f6f70SBen Gras
436d65f6f70SBen Gras while((sd = LIST_FIRST(&ip->i_lfs_segdhd)) != NULL) {
437d65f6f70SBen Gras LIST_REMOVE(sd, list);
438d65f6f70SBen Gras LIST_INSERT_HEAD(&fs->lfs_segdhd, sd, list);
439d65f6f70SBen Gras }
440d65f6f70SBen Gras }
441d65f6f70SBen Gras } else {
442d65f6f70SBen Gras /*
443d65f6f70SBen Gras * If it's not a dirop, we can finalize right away.
444d65f6f70SBen Gras */
445d65f6f70SBen Gras mutex_exit(&lfs_lock);
446d65f6f70SBen Gras lfs_finalize_ino_seguse(fs, ip);
447d65f6f70SBen Gras }
448d65f6f70SBen Gras
449d65f6f70SBen Gras mutex_enter(&lfs_lock);
450d65f6f70SBen Gras LFS_CLR_UINO(ip, IN_ACCESSED|IN_CLEANING|IN_MODIFIED);
451d65f6f70SBen Gras mutex_exit(&lfs_lock);
452d65f6f70SBen Gras ip->i_flag &= ~IN_ALLMOD;
453d65f6f70SBen Gras ip->i_lfs_iflags |= LFSI_DELETED;
454d65f6f70SBen Gras
455d65f6f70SBen Gras /*
456d65f6f70SBen Gras * Set the ifile's inode entry to unused, increment its version number
457d65f6f70SBen Gras * and link it onto the free chain.
458d65f6f70SBen Gras */
459d65f6f70SBen Gras SET_BITMAP_FREE(fs, ino);
460d65f6f70SBen Gras LFS_IENTRY(ifp, fs, ino, bp);
461*0a6a1f1dSLionel Sambuc old_iaddr = lfs_if_getdaddr(fs, ifp);
462*0a6a1f1dSLionel Sambuc lfs_if_setdaddr(fs, ifp, LFS_UNUSED_DADDR);
463*0a6a1f1dSLionel Sambuc lfs_if_setversion(fs, ifp, lfs_if_getversion(fs, ifp) + 1);
464*0a6a1f1dSLionel Sambuc if (lfs_sb_getversion(fs) == 1) {
465*0a6a1f1dSLionel Sambuc ino_t nextfree;
466*0a6a1f1dSLionel Sambuc
467*0a6a1f1dSLionel Sambuc LFS_GET_HEADFREE(fs, cip, cbp, &nextfree);
468*0a6a1f1dSLionel Sambuc lfs_if_setnextfree(fs, ifp, nextfree);
469d65f6f70SBen Gras LFS_PUT_HEADFREE(fs, cip, cbp, ino);
470d65f6f70SBen Gras (void) LFS_BWRITE_LOG(bp); /* Ifile */
471d65f6f70SBen Gras } else {
472d65f6f70SBen Gras ino_t tino, onf;
473d65f6f70SBen Gras
474*0a6a1f1dSLionel Sambuc lfs_if_setnextfree(fs, ifp, LFS_UNUSED_INUM);
475d65f6f70SBen Gras (void) LFS_BWRITE_LOG(bp); /* Ifile */
476d65f6f70SBen Gras
477d65f6f70SBen Gras tino = lfs_freelist_prev(fs, ino);
478d65f6f70SBen Gras if (tino == LFS_UNUSED_INUM) {
479*0a6a1f1dSLionel Sambuc ino_t nextfree;
480*0a6a1f1dSLionel Sambuc
481d65f6f70SBen Gras /* Nothing free below us, put us on the head */
482d65f6f70SBen Gras LFS_IENTRY(ifp, fs, ino, bp);
483*0a6a1f1dSLionel Sambuc LFS_GET_HEADFREE(fs, cip, cbp, &nextfree);
484*0a6a1f1dSLionel Sambuc lfs_if_setnextfree(fs, ifp, nextfree);
485d65f6f70SBen Gras LFS_PUT_HEADFREE(fs, cip, cbp, ino);
486d65f6f70SBen Gras DLOG((DLOG_ALLOC, "lfs_vfree: headfree %lld -> %lld\n",
487*0a6a1f1dSLionel Sambuc (long long)nextfree, (long long)ino));
488d65f6f70SBen Gras LFS_BWRITE_LOG(bp); /* Ifile */
489d65f6f70SBen Gras
490d65f6f70SBen Gras /* If the list was empty, set tail too */
491d65f6f70SBen Gras LFS_GET_TAILFREE(fs, cip, cbp, &otail);
492d65f6f70SBen Gras if (otail == LFS_UNUSED_INUM) {
493d65f6f70SBen Gras LFS_PUT_TAILFREE(fs, cip, cbp, ino);
494d65f6f70SBen Gras DLOG((DLOG_ALLOC, "lfs_vfree: tailfree %lld "
495d65f6f70SBen Gras "-> %lld\n", (long long)otail,
496d65f6f70SBen Gras (long long)ino));
497d65f6f70SBen Gras }
498d65f6f70SBen Gras } else {
499d65f6f70SBen Gras /*
500d65f6f70SBen Gras * Insert this inode into the list after tino.
501d65f6f70SBen Gras * We hold the segment lock so we don't have to
502d65f6f70SBen Gras * worry about blocks being written out of order.
503d65f6f70SBen Gras */
504d65f6f70SBen Gras DLOG((DLOG_ALLOC, "lfs_vfree: insert ino %lld "
505d65f6f70SBen Gras " after %lld\n", ino, tino));
506d65f6f70SBen Gras
507d65f6f70SBen Gras LFS_IENTRY(ifp, fs, tino, bp);
508*0a6a1f1dSLionel Sambuc onf = lfs_if_getnextfree(fs, ifp);
509*0a6a1f1dSLionel Sambuc lfs_if_setnextfree(fs, ifp, ino);
510d65f6f70SBen Gras LFS_BWRITE_LOG(bp); /* Ifile */
511d65f6f70SBen Gras
512d65f6f70SBen Gras LFS_IENTRY(ifp, fs, ino, bp);
513*0a6a1f1dSLionel Sambuc lfs_if_setnextfree(fs, ifp, onf);
514d65f6f70SBen Gras LFS_BWRITE_LOG(bp); /* Ifile */
515d65f6f70SBen Gras
516d65f6f70SBen Gras /* If we're last, put us on the tail */
517d65f6f70SBen Gras if (onf == LFS_UNUSED_INUM) {
518d65f6f70SBen Gras LFS_GET_TAILFREE(fs, cip, cbp, &otail);
519d65f6f70SBen Gras LFS_PUT_TAILFREE(fs, cip, cbp, ino);
520d65f6f70SBen Gras DLOG((DLOG_ALLOC, "lfs_vfree: tailfree %lld "
521d65f6f70SBen Gras "-> %lld\n", (long long)otail,
522d65f6f70SBen Gras (long long)ino));
523d65f6f70SBen Gras }
524d65f6f70SBen Gras }
525d65f6f70SBen Gras }
526d65f6f70SBen Gras #ifdef DIAGNOSTIC
527d65f6f70SBen Gras if (ino == LFS_UNUSED_INUM) {
528d65f6f70SBen Gras panic("inode 0 freed");
529d65f6f70SBen Gras }
530d65f6f70SBen Gras #endif /* DIAGNOSTIC */
531d65f6f70SBen Gras if (old_iaddr != LFS_UNUSED_DADDR) {
53284d9c625SLionel Sambuc LFS_SEGENTRY(sup, fs, lfs_dtosn(fs, old_iaddr), bp);
533d65f6f70SBen Gras #ifdef DIAGNOSTIC
534*0a6a1f1dSLionel Sambuc if (sup->su_nbytes < DINOSIZE(fs)) {
535d65f6f70SBen Gras printf("lfs_vfree: negative byte count"
536d65f6f70SBen Gras " (segment %" PRIu32 " short by %d)\n",
53784d9c625SLionel Sambuc lfs_dtosn(fs, old_iaddr),
538*0a6a1f1dSLionel Sambuc (int)DINOSIZE(fs) -
539d65f6f70SBen Gras sup->su_nbytes);
540d65f6f70SBen Gras panic("lfs_vfree: negative byte count");
541*0a6a1f1dSLionel Sambuc sup->su_nbytes = DINOSIZE(fs);
542d65f6f70SBen Gras }
543d65f6f70SBen Gras #endif
544*0a6a1f1dSLionel Sambuc sup->su_nbytes -= DINOSIZE(fs);
54584d9c625SLionel Sambuc LFS_WRITESEGENTRY(sup, fs, lfs_dtosn(fs, old_iaddr), bp); /* Ifile */
546d65f6f70SBen Gras }
547d65f6f70SBen Gras
548d65f6f70SBen Gras /* Set superblock modified bit and decrement file count. */
549d65f6f70SBen Gras mutex_enter(&lfs_lock);
550d65f6f70SBen Gras fs->lfs_fmod = 1;
551d65f6f70SBen Gras mutex_exit(&lfs_lock);
552*0a6a1f1dSLionel Sambuc lfs_sb_subnfiles(fs, 1);
553d65f6f70SBen Gras
554d65f6f70SBen Gras lfs_segunlock(fs);
555d65f6f70SBen Gras
556d65f6f70SBen Gras return (0);
557d65f6f70SBen Gras }
558d65f6f70SBen Gras
559d65f6f70SBen Gras /*
560d65f6f70SBen Gras * Sort the freelist and set up the free-inode bitmap.
561d65f6f70SBen Gras * To be called by lfs_mountfs().
562d65f6f70SBen Gras */
563d65f6f70SBen Gras void
lfs_order_freelist(struct lfs * fs)564d65f6f70SBen Gras lfs_order_freelist(struct lfs *fs)
565d65f6f70SBen Gras {
566d65f6f70SBen Gras CLEANERINFO *cip;
567d65f6f70SBen Gras IFILE *ifp = NULL;
568d65f6f70SBen Gras struct buf *bp;
569d65f6f70SBen Gras ino_t ino, firstino, lastino, maxino;
570d65f6f70SBen Gras #ifdef notyet
571d65f6f70SBen Gras struct vnode *vp;
572d65f6f70SBen Gras #endif
573d65f6f70SBen Gras
574d65f6f70SBen Gras ASSERT_NO_SEGLOCK(fs);
575d65f6f70SBen Gras lfs_seglock(fs, SEGM_PROT);
576d65f6f70SBen Gras
577*0a6a1f1dSLionel Sambuc maxino = ((fs->lfs_ivnode->v_size >> lfs_sb_getbshift(fs)) -
578*0a6a1f1dSLionel Sambuc lfs_sb_getcleansz(fs) - lfs_sb_getsegtabsz(fs)) * lfs_sb_getifpb(fs);
579*0a6a1f1dSLionel Sambuc fs->lfs_ino_bitmap =
580d65f6f70SBen Gras malloc(((maxino + BMMASK) >> BMSHIFT) * sizeof(lfs_bm_t),
581d65f6f70SBen Gras M_SEGMENT, M_WAITOK | M_ZERO);
582d65f6f70SBen Gras KASSERT(fs->lfs_ino_bitmap != NULL);
583d65f6f70SBen Gras
584d65f6f70SBen Gras firstino = lastino = LFS_UNUSED_INUM;
585d65f6f70SBen Gras for (ino = 0; ino < maxino; ino++) {
586*0a6a1f1dSLionel Sambuc if (ino % lfs_sb_getifpb(fs) == 0)
587d65f6f70SBen Gras LFS_IENTRY(ifp, fs, ino, bp);
588d65f6f70SBen Gras else
589*0a6a1f1dSLionel Sambuc LFS_IENTRY_NEXT(ifp, fs);
590d65f6f70SBen Gras
591d65f6f70SBen Gras /* Don't put zero or ifile on the free list */
592d65f6f70SBen Gras if (ino == LFS_UNUSED_INUM || ino == LFS_IFILE_INUM)
593d65f6f70SBen Gras continue;
594d65f6f70SBen Gras
595d65f6f70SBen Gras #ifdef notyet
596d65f6f70SBen Gras /* Address orphaned files */
597*0a6a1f1dSLionel Sambuc if (lfs_if_getnextfree(fs, ifp) == LFS_ORPHAN_NEXTFREE &&
598d65f6f70SBen Gras VFS_VGET(fs->lfs_ivnode->v_mount, ino, &vp) == 0) {
599*0a6a1f1dSLionel Sambuc unsigned segno;
600*0a6a1f1dSLionel Sambuc
601*0a6a1f1dSLionel Sambuc segno = lfs_dtosn(fs, lfs_if_getdaddr(fs, ifp));
602d65f6f70SBen Gras lfs_truncate(vp, 0, 0, NOCRED);
603d65f6f70SBen Gras vput(vp);
604*0a6a1f1dSLionel Sambuc LFS_SEGENTRY(sup, fs, segno, bp);
605*0a6a1f1dSLionel Sambuc KASSERT(sup->su_nbytes >= LFS_DINODE1_SIZE);
606*0a6a1f1dSLionel Sambuc sup->su_nbytes -= LFS_DINODE1_SIZE;
607*0a6a1f1dSLionel Sambuc LFS_WRITESEGENTRY(sup, fs, segno, bp);
608d65f6f70SBen Gras
609d65f6f70SBen Gras /* Set up to fall through to next section */
610*0a6a1f1dSLionel Sambuc lfs_if_setdaddr(fs, ifp, LFS_UNUSED_DADDR);
611d65f6f70SBen Gras LFS_BWRITE_LOG(bp);
612d65f6f70SBen Gras LFS_IENTRY(ifp, fs, ino, bp);
613d65f6f70SBen Gras }
614d65f6f70SBen Gras #endif
615d65f6f70SBen Gras
616*0a6a1f1dSLionel Sambuc if (lfs_if_getdaddr(fs, ifp) == LFS_UNUSED_DADDR) {
617d65f6f70SBen Gras if (firstino == LFS_UNUSED_INUM)
618d65f6f70SBen Gras firstino = ino;
619d65f6f70SBen Gras else {
620d65f6f70SBen Gras brelse(bp, 0);
621d65f6f70SBen Gras
622d65f6f70SBen Gras LFS_IENTRY(ifp, fs, lastino, bp);
623*0a6a1f1dSLionel Sambuc lfs_if_setnextfree(fs, ifp, ino);
624d65f6f70SBen Gras LFS_BWRITE_LOG(bp);
625d65f6f70SBen Gras
626d65f6f70SBen Gras LFS_IENTRY(ifp, fs, ino, bp);
627d65f6f70SBen Gras }
628d65f6f70SBen Gras lastino = ino;
629d65f6f70SBen Gras
630d65f6f70SBen Gras SET_BITMAP_FREE(fs, ino);
631d65f6f70SBen Gras }
632d65f6f70SBen Gras
633*0a6a1f1dSLionel Sambuc if ((ino + 1) % lfs_sb_getifpb(fs) == 0)
634d65f6f70SBen Gras brelse(bp, 0);
635d65f6f70SBen Gras }
636d65f6f70SBen Gras
637d65f6f70SBen Gras LFS_PUT_HEADFREE(fs, cip, bp, firstino);
638d65f6f70SBen Gras LFS_PUT_TAILFREE(fs, cip, bp, lastino);
639d65f6f70SBen Gras
640d65f6f70SBen Gras lfs_segunlock(fs);
641d65f6f70SBen Gras }
642d65f6f70SBen Gras
643d65f6f70SBen Gras void
lfs_orphan(struct lfs * fs,ino_t ino)644d65f6f70SBen Gras lfs_orphan(struct lfs *fs, ino_t ino)
645d65f6f70SBen Gras {
646d65f6f70SBen Gras IFILE *ifp;
647d65f6f70SBen Gras struct buf *bp;
648d65f6f70SBen Gras
649d65f6f70SBen Gras LFS_IENTRY(ifp, fs, ino, bp);
650*0a6a1f1dSLionel Sambuc lfs_if_setnextfree(fs, ifp, LFS_ORPHAN_NEXTFREE);
651d65f6f70SBen Gras LFS_BWRITE_LOG(bp);
652d65f6f70SBen Gras }
653