1*0a6a1f1dSLionel Sambuc /* $NetBSD: lfs_syscalls.c,v 1.170 2015/09/01 06:08:37 dholland Exp $ */
2d65f6f70SBen Gras
3d65f6f70SBen Gras /*-
4d65f6f70SBen Gras * Copyright (c) 1999, 2000, 2001, 2002, 2003, 2007, 2007, 2008
5d65f6f70SBen Gras * The NetBSD Foundation, Inc.
6d65f6f70SBen Gras * All rights reserved.
7d65f6f70SBen Gras *
8d65f6f70SBen Gras * This code is derived from software contributed to The NetBSD Foundation
9d65f6f70SBen Gras * by Konrad E. Schroder <perseant@hhhh.org>.
10d65f6f70SBen Gras *
11d65f6f70SBen Gras * Redistribution and use in source and binary forms, with or without
12d65f6f70SBen Gras * modification, are permitted provided that the following conditions
13d65f6f70SBen Gras * are met:
14d65f6f70SBen Gras * 1. Redistributions of source code must retain the above copyright
15d65f6f70SBen Gras * notice, this list of conditions and the following disclaimer.
16d65f6f70SBen Gras * 2. Redistributions in binary form must reproduce the above copyright
17d65f6f70SBen Gras * notice, this list of conditions and the following disclaimer in the
18d65f6f70SBen Gras * documentation and/or other materials provided with the distribution.
19d65f6f70SBen Gras *
20d65f6f70SBen Gras * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21d65f6f70SBen Gras * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22d65f6f70SBen Gras * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23d65f6f70SBen Gras * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24d65f6f70SBen Gras * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25d65f6f70SBen Gras * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26d65f6f70SBen Gras * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27d65f6f70SBen Gras * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28d65f6f70SBen Gras * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29d65f6f70SBen Gras * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30d65f6f70SBen Gras * POSSIBILITY OF SUCH DAMAGE.
31d65f6f70SBen Gras */
32d65f6f70SBen Gras /*-
33d65f6f70SBen Gras * Copyright (c) 1991, 1993, 1994
34d65f6f70SBen Gras * The Regents of the University of California. All rights reserved.
35d65f6f70SBen Gras *
36d65f6f70SBen Gras * Redistribution and use in source and binary forms, with or without
37d65f6f70SBen Gras * modification, are permitted provided that the following conditions
38d65f6f70SBen Gras * are met:
39d65f6f70SBen Gras * 1. Redistributions of source code must retain the above copyright
40d65f6f70SBen Gras * notice, this list of conditions and the following disclaimer.
41d65f6f70SBen Gras * 2. Redistributions in binary form must reproduce the above copyright
42d65f6f70SBen Gras * notice, this list of conditions and the following disclaimer in the
43d65f6f70SBen Gras * documentation and/or other materials provided with the distribution.
44d65f6f70SBen Gras * 3. Neither the name of the University nor the names of its contributors
45d65f6f70SBen Gras * may be used to endorse or promote products derived from this software
46d65f6f70SBen Gras * without specific prior written permission.
47d65f6f70SBen Gras *
48d65f6f70SBen Gras * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49d65f6f70SBen Gras * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50d65f6f70SBen Gras * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51d65f6f70SBen Gras * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52d65f6f70SBen Gras * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53d65f6f70SBen Gras * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54d65f6f70SBen Gras * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55d65f6f70SBen Gras * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56d65f6f70SBen Gras * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57d65f6f70SBen Gras * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58d65f6f70SBen Gras * SUCH DAMAGE.
59d65f6f70SBen Gras *
60d65f6f70SBen Gras * @(#)lfs_syscalls.c 8.10 (Berkeley) 5/14/95
61d65f6f70SBen Gras */
62d65f6f70SBen Gras
63d65f6f70SBen Gras #include <sys/cdefs.h>
64*0a6a1f1dSLionel Sambuc __KERNEL_RCSID(0, "$NetBSD: lfs_syscalls.c,v 1.170 2015/09/01 06:08:37 dholland Exp $");
65d65f6f70SBen Gras
66d65f6f70SBen Gras #ifndef LFS
67d65f6f70SBen Gras # define LFS /* for prototypes in syscallargs.h */
68d65f6f70SBen Gras #endif
69d65f6f70SBen Gras
70d65f6f70SBen Gras #include <sys/param.h>
71d65f6f70SBen Gras #include <sys/systm.h>
72d65f6f70SBen Gras #include <sys/proc.h>
73d65f6f70SBen Gras #include <sys/buf.h>
74d65f6f70SBen Gras #include <sys/mount.h>
75d65f6f70SBen Gras #include <sys/vnode.h>
76d65f6f70SBen Gras #include <sys/kernel.h>
77d65f6f70SBen Gras #include <sys/kauth.h>
78d65f6f70SBen Gras #include <sys/syscallargs.h>
79d65f6f70SBen Gras
8084d9c625SLionel Sambuc #include <ufs/lfs/ulfs_inode.h>
8184d9c625SLionel Sambuc #include <ufs/lfs/ulfsmount.h>
8284d9c625SLionel Sambuc #include <ufs/lfs/ulfs_extern.h>
83d65f6f70SBen Gras
84d65f6f70SBen Gras #include <ufs/lfs/lfs.h>
85*0a6a1f1dSLionel Sambuc #include <ufs/lfs/lfs_accessors.h>
8684d9c625SLionel Sambuc #include <ufs/lfs/lfs_kernel.h>
87d65f6f70SBen Gras #include <ufs/lfs/lfs_extern.h>
88d65f6f70SBen Gras
89*0a6a1f1dSLionel Sambuc static int lfs_fastvget(struct mount *, ino_t, BLOCK_INFO *, int,
90*0a6a1f1dSLionel Sambuc struct vnode **);
91*0a6a1f1dSLionel Sambuc static struct buf *lfs_fakebuf(struct lfs *, struct vnode *, daddr_t,
92*0a6a1f1dSLionel Sambuc size_t, void *);
93d65f6f70SBen Gras
94d65f6f70SBen Gras /*
95d65f6f70SBen Gras * sys_lfs_markv:
96d65f6f70SBen Gras *
97d65f6f70SBen Gras * This will mark inodes and blocks dirty, so they are written into the log.
98d65f6f70SBen Gras * It will block until all the blocks have been written. The segment create
99d65f6f70SBen Gras * time passed in the block_info and inode_info structures is used to decide
100d65f6f70SBen Gras * if the data is valid for each block (in case some process dirtied a block
101d65f6f70SBen Gras * or inode that is being cleaned between the determination that a block is
102d65f6f70SBen Gras * live and the lfs_markv call).
103d65f6f70SBen Gras *
104d65f6f70SBen Gras * 0 on success
105d65f6f70SBen Gras * -1/errno is return on error.
106d65f6f70SBen Gras */
107d65f6f70SBen Gras #ifdef USE_64BIT_SYSCALLS
108d65f6f70SBen Gras int
sys_lfs_markv(struct lwp * l,const struct sys_lfs_markv_args * uap,register_t * retval)109d65f6f70SBen Gras sys_lfs_markv(struct lwp *l, const struct sys_lfs_markv_args *uap, register_t *retval)
110d65f6f70SBen Gras {
111d65f6f70SBen Gras /* {
112d65f6f70SBen Gras syscallarg(fsid_t *) fsidp;
113d65f6f70SBen Gras syscallarg(struct block_info *) blkiov;
114d65f6f70SBen Gras syscallarg(int) blkcnt;
115d65f6f70SBen Gras } */
116d65f6f70SBen Gras BLOCK_INFO *blkiov;
117d65f6f70SBen Gras int blkcnt, error;
118d65f6f70SBen Gras fsid_t fsid;
119d65f6f70SBen Gras struct lfs *fs;
120d65f6f70SBen Gras struct mount *mntp;
121d65f6f70SBen Gras
122d65f6f70SBen Gras if ((error = copyin(SCARG(uap, fsidp), &fsid, sizeof(fsid_t))) != 0)
123d65f6f70SBen Gras return (error);
124d65f6f70SBen Gras
125d65f6f70SBen Gras if ((mntp = vfs_getvfs(fsidp)) == NULL)
126d65f6f70SBen Gras return (ENOENT);
12784d9c625SLionel Sambuc fs = VFSTOULFS(mntp)->um_lfs;
128d65f6f70SBen Gras
129d65f6f70SBen Gras blkcnt = SCARG(uap, blkcnt);
130d65f6f70SBen Gras if ((u_int) blkcnt > LFS_MARKV_MAXBLKCNT)
131d65f6f70SBen Gras return (EINVAL);
132d65f6f70SBen Gras
133d65f6f70SBen Gras KERNEL_LOCK(1, NULL);
134d65f6f70SBen Gras blkiov = lfs_malloc(fs, blkcnt * sizeof(BLOCK_INFO), LFS_NB_BLKIOV);
135d65f6f70SBen Gras if ((error = copyin(SCARG(uap, blkiov), blkiov,
136d65f6f70SBen Gras blkcnt * sizeof(BLOCK_INFO))) != 0)
137d65f6f70SBen Gras goto out;
138d65f6f70SBen Gras
139d65f6f70SBen Gras if ((error = lfs_markv(p, &fsid, blkiov, blkcnt)) == 0)
140d65f6f70SBen Gras copyout(blkiov, SCARG(uap, blkiov),
141d65f6f70SBen Gras blkcnt * sizeof(BLOCK_INFO));
142d65f6f70SBen Gras out:
143d65f6f70SBen Gras lfs_free(fs, blkiov, LFS_NB_BLKIOV);
144d65f6f70SBen Gras KERNEL_UNLOCK_ONE(NULL);
145d65f6f70SBen Gras return error;
146d65f6f70SBen Gras }
147d65f6f70SBen Gras #else
148d65f6f70SBen Gras int
sys_lfs_markv(struct lwp * l,const struct sys_lfs_markv_args * uap,register_t * retval)149d65f6f70SBen Gras sys_lfs_markv(struct lwp *l, const struct sys_lfs_markv_args *uap, register_t *retval)
150d65f6f70SBen Gras {
151d65f6f70SBen Gras /* {
152d65f6f70SBen Gras syscallarg(fsid_t *) fsidp;
153d65f6f70SBen Gras syscallarg(struct block_info *) blkiov;
154d65f6f70SBen Gras syscallarg(int) blkcnt;
155d65f6f70SBen Gras } */
156d65f6f70SBen Gras BLOCK_INFO *blkiov;
157d65f6f70SBen Gras BLOCK_INFO_15 *blkiov15;
158d65f6f70SBen Gras int i, blkcnt, error;
159d65f6f70SBen Gras fsid_t fsid;
160d65f6f70SBen Gras struct lfs *fs;
161d65f6f70SBen Gras struct mount *mntp;
162d65f6f70SBen Gras
163d65f6f70SBen Gras if ((error = copyin(SCARG(uap, fsidp), &fsid, sizeof(fsid_t))) != 0)
164d65f6f70SBen Gras return (error);
165d65f6f70SBen Gras
166d65f6f70SBen Gras if ((mntp = vfs_getvfs(&fsid)) == NULL)
167d65f6f70SBen Gras return (ENOENT);
16884d9c625SLionel Sambuc fs = VFSTOULFS(mntp)->um_lfs;
169d65f6f70SBen Gras
170d65f6f70SBen Gras blkcnt = SCARG(uap, blkcnt);
171d65f6f70SBen Gras if ((u_int) blkcnt > LFS_MARKV_MAXBLKCNT)
172d65f6f70SBen Gras return (EINVAL);
173d65f6f70SBen Gras
174d65f6f70SBen Gras KERNEL_LOCK(1, NULL);
175d65f6f70SBen Gras blkiov = lfs_malloc(fs, blkcnt * sizeof(BLOCK_INFO), LFS_NB_BLKIOV);
176d65f6f70SBen Gras blkiov15 = lfs_malloc(fs, blkcnt * sizeof(BLOCK_INFO_15), LFS_NB_BLKIOV);
177d65f6f70SBen Gras if ((error = copyin(SCARG(uap, blkiov), blkiov15,
178d65f6f70SBen Gras blkcnt * sizeof(BLOCK_INFO_15))) != 0)
179d65f6f70SBen Gras goto out;
180d65f6f70SBen Gras
181d65f6f70SBen Gras for (i = 0; i < blkcnt; i++) {
182d65f6f70SBen Gras blkiov[i].bi_inode = blkiov15[i].bi_inode;
183d65f6f70SBen Gras blkiov[i].bi_lbn = blkiov15[i].bi_lbn;
184d65f6f70SBen Gras blkiov[i].bi_daddr = blkiov15[i].bi_daddr;
185d65f6f70SBen Gras blkiov[i].bi_segcreate = blkiov15[i].bi_segcreate;
186d65f6f70SBen Gras blkiov[i].bi_version = blkiov15[i].bi_version;
187d65f6f70SBen Gras blkiov[i].bi_bp = blkiov15[i].bi_bp;
188d65f6f70SBen Gras blkiov[i].bi_size = blkiov15[i].bi_size;
189d65f6f70SBen Gras }
190d65f6f70SBen Gras
191*0a6a1f1dSLionel Sambuc if ((error = lfs_markv(l, &fsid, blkiov, blkcnt)) == 0) {
192d65f6f70SBen Gras for (i = 0; i < blkcnt; i++) {
193d65f6f70SBen Gras blkiov15[i].bi_inode = blkiov[i].bi_inode;
194d65f6f70SBen Gras blkiov15[i].bi_lbn = blkiov[i].bi_lbn;
195d65f6f70SBen Gras blkiov15[i].bi_daddr = blkiov[i].bi_daddr;
196d65f6f70SBen Gras blkiov15[i].bi_segcreate = blkiov[i].bi_segcreate;
197d65f6f70SBen Gras blkiov15[i].bi_version = blkiov[i].bi_version;
198d65f6f70SBen Gras blkiov15[i].bi_bp = blkiov[i].bi_bp;
199d65f6f70SBen Gras blkiov15[i].bi_size = blkiov[i].bi_size;
200d65f6f70SBen Gras }
201d65f6f70SBen Gras copyout(blkiov15, SCARG(uap, blkiov),
202d65f6f70SBen Gras blkcnt * sizeof(BLOCK_INFO_15));
203d65f6f70SBen Gras }
204d65f6f70SBen Gras out:
205d65f6f70SBen Gras lfs_free(fs, blkiov, LFS_NB_BLKIOV);
206d65f6f70SBen Gras lfs_free(fs, blkiov15, LFS_NB_BLKIOV);
207d65f6f70SBen Gras KERNEL_UNLOCK_ONE(NULL);
208d65f6f70SBen Gras return error;
209d65f6f70SBen Gras }
210d65f6f70SBen Gras #endif
211d65f6f70SBen Gras
212d65f6f70SBen Gras #define LFS_MARKV_MAX_BLOCKS (LFS_MAX_BUFS)
213d65f6f70SBen Gras
214d65f6f70SBen Gras int
lfs_markv(struct lwp * l,fsid_t * fsidp,BLOCK_INFO * blkiov,int blkcnt)215*0a6a1f1dSLionel Sambuc lfs_markv(struct lwp *l, fsid_t *fsidp, BLOCK_INFO *blkiov,
216d65f6f70SBen Gras int blkcnt)
217d65f6f70SBen Gras {
218d65f6f70SBen Gras BLOCK_INFO *blkp;
219d65f6f70SBen Gras IFILE *ifp;
220d65f6f70SBen Gras struct buf *bp;
221d65f6f70SBen Gras struct inode *ip = NULL;
222d65f6f70SBen Gras struct lfs *fs;
223d65f6f70SBen Gras struct mount *mntp;
224*0a6a1f1dSLionel Sambuc struct ulfsmount *ump;
225*0a6a1f1dSLionel Sambuc struct vnode *vp;
226d65f6f70SBen Gras ino_t lastino;
227*0a6a1f1dSLionel Sambuc daddr_t b_daddr;
228d65f6f70SBen Gras int cnt, error;
229d65f6f70SBen Gras int do_again = 0;
230d65f6f70SBen Gras int numrefed = 0;
231d65f6f70SBen Gras ino_t maxino;
232d65f6f70SBen Gras size_t obsize;
233d65f6f70SBen Gras
234d65f6f70SBen Gras /* number of blocks/inodes that we have already bwrite'ed */
235d65f6f70SBen Gras int nblkwritten, ninowritten;
236d65f6f70SBen Gras
237*0a6a1f1dSLionel Sambuc error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_LFS,
238*0a6a1f1dSLionel Sambuc KAUTH_REQ_SYSTEM_LFS_MARKV, NULL, NULL, NULL);
239*0a6a1f1dSLionel Sambuc if (error)
240*0a6a1f1dSLionel Sambuc return (error);
241*0a6a1f1dSLionel Sambuc
242d65f6f70SBen Gras if ((mntp = vfs_getvfs(fsidp)) == NULL)
243d65f6f70SBen Gras return (ENOENT);
244d65f6f70SBen Gras
245*0a6a1f1dSLionel Sambuc ump = VFSTOULFS(mntp);
246*0a6a1f1dSLionel Sambuc fs = ump->um_lfs;
247d65f6f70SBen Gras
248d65f6f70SBen Gras if (fs->lfs_ronly)
249d65f6f70SBen Gras return EROFS;
250d65f6f70SBen Gras
251*0a6a1f1dSLionel Sambuc maxino = (lfs_fragstoblks(fs, lfs_dino_getblocks(fs, VTOI(fs->lfs_ivnode)->i_din)) -
252*0a6a1f1dSLionel Sambuc lfs_sb_getcleansz(fs) - lfs_sb_getsegtabsz(fs)) * lfs_sb_getifpb(fs);
253d65f6f70SBen Gras
254d65f6f70SBen Gras cnt = blkcnt;
255d65f6f70SBen Gras
256d65f6f70SBen Gras if ((error = vfs_busy(mntp, NULL)) != 0)
257d65f6f70SBen Gras return (error);
258d65f6f70SBen Gras
259d65f6f70SBen Gras /*
260d65f6f70SBen Gras * This seglock is just to prevent the fact that we might have to sleep
261d65f6f70SBen Gras * from allowing the possibility that our blocks might become
262d65f6f70SBen Gras * invalid.
263d65f6f70SBen Gras *
264d65f6f70SBen Gras * It is also important to note here that unless we specify SEGM_CKP,
265d65f6f70SBen Gras * any Ifile blocks that we might be asked to clean will never get
266d65f6f70SBen Gras * to the disk.
267d65f6f70SBen Gras */
268d65f6f70SBen Gras lfs_seglock(fs, SEGM_CLEAN | SEGM_CKP | SEGM_SYNC);
269d65f6f70SBen Gras
270d65f6f70SBen Gras /* Mark blocks/inodes dirty. */
271d65f6f70SBen Gras error = 0;
272d65f6f70SBen Gras
273d65f6f70SBen Gras /* these were inside the initialization for the for loop */
274*0a6a1f1dSLionel Sambuc vp = NULL;
275d65f6f70SBen Gras lastino = LFS_UNUSED_INUM;
276d65f6f70SBen Gras nblkwritten = ninowritten = 0;
277d65f6f70SBen Gras for (blkp = blkiov; cnt--; ++blkp)
278d65f6f70SBen Gras {
279d65f6f70SBen Gras /* Bounds-check incoming data, avoid panic for failed VGET */
280d65f6f70SBen Gras if (blkp->bi_inode <= 0 || blkp->bi_inode >= maxino) {
281d65f6f70SBen Gras error = EINVAL;
282d65f6f70SBen Gras goto err3;
283d65f6f70SBen Gras }
284d65f6f70SBen Gras /*
285d65f6f70SBen Gras * Get the IFILE entry (only once) and see if the file still
286d65f6f70SBen Gras * exists.
287d65f6f70SBen Gras */
288d65f6f70SBen Gras if (lastino != blkp->bi_inode) {
289d65f6f70SBen Gras /*
290*0a6a1f1dSLionel Sambuc * Finish the old file, if there was one.
291d65f6f70SBen Gras */
292*0a6a1f1dSLionel Sambuc if (vp != NULL) {
293*0a6a1f1dSLionel Sambuc vput(vp);
294*0a6a1f1dSLionel Sambuc vp = NULL;
295d65f6f70SBen Gras numrefed--;
296d65f6f70SBen Gras }
297d65f6f70SBen Gras
298d65f6f70SBen Gras /*
299d65f6f70SBen Gras * Start a new file
300d65f6f70SBen Gras */
301d65f6f70SBen Gras lastino = blkp->bi_inode;
302d65f6f70SBen Gras
303d65f6f70SBen Gras /* Get the vnode/inode. */
304*0a6a1f1dSLionel Sambuc error = lfs_fastvget(mntp, blkp->bi_inode, blkp,
305*0a6a1f1dSLionel Sambuc LK_EXCLUSIVE | LK_NOWAIT, &vp);
306d65f6f70SBen Gras if (error) {
307d65f6f70SBen Gras DLOG((DLOG_CLEAN, "lfs_markv: lfs_fastvget"
308d65f6f70SBen Gras " failed with %d (ino %d, segment %d)\n",
309d65f6f70SBen Gras error, blkp->bi_inode,
31084d9c625SLionel Sambuc lfs_dtosn(fs, blkp->bi_daddr)));
311d65f6f70SBen Gras /*
312d65f6f70SBen Gras * If we got EAGAIN, that means that the
313d65f6f70SBen Gras * Inode was locked. This is
314d65f6f70SBen Gras * recoverable: just clean the rest of
315d65f6f70SBen Gras * this segment, and let the cleaner try
316d65f6f70SBen Gras * again with another. (When the
317d65f6f70SBen Gras * cleaner runs again, this segment will
318d65f6f70SBen Gras * sort high on the list, since it is
319*0a6a1f1dSLionel Sambuc * now almost entirely empty.)
320d65f6f70SBen Gras */
321d65f6f70SBen Gras if (error == EAGAIN) {
322d65f6f70SBen Gras error = 0;
323d65f6f70SBen Gras do_again++;
324*0a6a1f1dSLionel Sambuc } else
325*0a6a1f1dSLionel Sambuc KASSERT(error == ENOENT);
326*0a6a1f1dSLionel Sambuc KASSERT(vp == NULL);
327d65f6f70SBen Gras ip = NULL;
328d65f6f70SBen Gras continue;
329d65f6f70SBen Gras }
330*0a6a1f1dSLionel Sambuc
331d65f6f70SBen Gras ip = VTOI(vp);
332*0a6a1f1dSLionel Sambuc numrefed++;
333d65f6f70SBen Gras ninowritten++;
334*0a6a1f1dSLionel Sambuc } else if (vp == NULL) {
335d65f6f70SBen Gras /*
336d65f6f70SBen Gras * This can only happen if the vnode is dead (or
337d65f6f70SBen Gras * in any case we can't get it...e.g., it is
338d65f6f70SBen Gras * inlocked). Keep going.
339d65f6f70SBen Gras */
340d65f6f70SBen Gras continue;
341d65f6f70SBen Gras }
342d65f6f70SBen Gras
343d65f6f70SBen Gras /* Past this point we are guaranteed that vp, ip are valid. */
344d65f6f70SBen Gras
345d65f6f70SBen Gras /* Can't clean VU_DIROP directories in case of truncation */
346d65f6f70SBen Gras /* XXX - maybe we should mark removed dirs specially? */
347d65f6f70SBen Gras if (vp->v_type == VDIR && (vp->v_uflag & VU_DIROP)) {
348d65f6f70SBen Gras do_again++;
349d65f6f70SBen Gras continue;
350d65f6f70SBen Gras }
351d65f6f70SBen Gras
352d65f6f70SBen Gras /* If this BLOCK_INFO didn't contain a block, keep going. */
353d65f6f70SBen Gras if (blkp->bi_lbn == LFS_UNUSED_LBN) {
354d65f6f70SBen Gras /* XXX need to make sure that the inode gets written in this case */
355d65f6f70SBen Gras /* XXX but only write the inode if it's the right one */
356d65f6f70SBen Gras if (blkp->bi_inode != LFS_IFILE_INUM) {
357d65f6f70SBen Gras LFS_IENTRY(ifp, fs, blkp->bi_inode, bp);
358*0a6a1f1dSLionel Sambuc if (lfs_if_getdaddr(fs, ifp) == blkp->bi_daddr) {
359d65f6f70SBen Gras mutex_enter(&lfs_lock);
360d65f6f70SBen Gras LFS_SET_UINO(ip, IN_CLEANING);
361d65f6f70SBen Gras mutex_exit(&lfs_lock);
362d65f6f70SBen Gras }
363d65f6f70SBen Gras brelse(bp, 0);
364d65f6f70SBen Gras }
365d65f6f70SBen Gras continue;
366d65f6f70SBen Gras }
367d65f6f70SBen Gras
368d65f6f70SBen Gras b_daddr = 0;
369d65f6f70SBen Gras if (VOP_BMAP(vp, blkp->bi_lbn, NULL, &b_daddr, NULL) ||
37084d9c625SLionel Sambuc LFS_DBTOFSB(fs, b_daddr) != blkp->bi_daddr)
371d65f6f70SBen Gras {
37284d9c625SLionel Sambuc if (lfs_dtosn(fs, LFS_DBTOFSB(fs, b_daddr)) ==
37384d9c625SLionel Sambuc lfs_dtosn(fs, blkp->bi_daddr))
374d65f6f70SBen Gras {
375*0a6a1f1dSLionel Sambuc DLOG((DLOG_CLEAN, "lfs_markv: wrong da same seg: %jx vs %jx\n",
376*0a6a1f1dSLionel Sambuc (intmax_t)blkp->bi_daddr, (intmax_t)LFS_DBTOFSB(fs, b_daddr)));
377d65f6f70SBen Gras }
378d65f6f70SBen Gras do_again++;
379d65f6f70SBen Gras continue;
380d65f6f70SBen Gras }
381d65f6f70SBen Gras
382d65f6f70SBen Gras /*
383d65f6f70SBen Gras * Check block sizes. The blocks being cleaned come from
384d65f6f70SBen Gras * disk, so they should have the same size as their on-disk
385d65f6f70SBen Gras * counterparts.
386d65f6f70SBen Gras */
387d65f6f70SBen Gras if (blkp->bi_lbn >= 0)
38884d9c625SLionel Sambuc obsize = lfs_blksize(fs, ip, blkp->bi_lbn);
389d65f6f70SBen Gras else
390*0a6a1f1dSLionel Sambuc obsize = lfs_sb_getbsize(fs);
391d65f6f70SBen Gras /* Check for fragment size change */
39284d9c625SLionel Sambuc if (blkp->bi_lbn >= 0 && blkp->bi_lbn < ULFS_NDADDR) {
393d65f6f70SBen Gras obsize = ip->i_lfs_fragsize[blkp->bi_lbn];
394d65f6f70SBen Gras }
395d65f6f70SBen Gras if (obsize != blkp->bi_size) {
396*0a6a1f1dSLionel Sambuc DLOG((DLOG_CLEAN, "lfs_markv: ino %d lbn %jd wrong"
397d65f6f70SBen Gras " size (%ld != %d), try again\n",
398*0a6a1f1dSLionel Sambuc blkp->bi_inode, (intmax_t)blkp->bi_lbn,
399d65f6f70SBen Gras (long) obsize, blkp->bi_size));
400d65f6f70SBen Gras do_again++;
401d65f6f70SBen Gras continue;
402d65f6f70SBen Gras }
403d65f6f70SBen Gras
404d65f6f70SBen Gras /*
405d65f6f70SBen Gras * If we get to here, then we are keeping the block. If
406d65f6f70SBen Gras * it is an indirect block, we want to actually put it
407d65f6f70SBen Gras * in the buffer cache so that it can be updated in the
408d65f6f70SBen Gras * finish_meta section. If it's not, we need to
409d65f6f70SBen Gras * allocate a fake buffer so that writeseg can perform
410d65f6f70SBen Gras * the copyin and write the buffer.
411d65f6f70SBen Gras */
412d65f6f70SBen Gras if (ip->i_number != LFS_IFILE_INUM && blkp->bi_lbn >= 0) {
413d65f6f70SBen Gras /* Data Block */
414d65f6f70SBen Gras bp = lfs_fakebuf(fs, vp, blkp->bi_lbn,
415d65f6f70SBen Gras blkp->bi_size, blkp->bi_bp);
416d65f6f70SBen Gras /* Pretend we used bread() to get it */
41784d9c625SLionel Sambuc bp->b_blkno = LFS_FSBTODB(fs, blkp->bi_daddr);
418d65f6f70SBen Gras } else {
419d65f6f70SBen Gras /* Indirect block or ifile */
420*0a6a1f1dSLionel Sambuc if (blkp->bi_size != lfs_sb_getbsize(fs) &&
421d65f6f70SBen Gras ip->i_number != LFS_IFILE_INUM)
422d65f6f70SBen Gras panic("lfs_markv: partial indirect block?"
423d65f6f70SBen Gras " size=%d\n", blkp->bi_size);
424d65f6f70SBen Gras bp = getblk(vp, blkp->bi_lbn, blkp->bi_size, 0, 0);
425d65f6f70SBen Gras if (!(bp->b_oflags & (BO_DONE|BO_DELWRI))) {
426d65f6f70SBen Gras /*
427d65f6f70SBen Gras * The block in question was not found
428d65f6f70SBen Gras * in the cache; i.e., the block that
429d65f6f70SBen Gras * getblk() returned is empty. So, we
430d65f6f70SBen Gras * can (and should) copy in the
431d65f6f70SBen Gras * contents, because we've already
432d65f6f70SBen Gras * determined that this was the right
433d65f6f70SBen Gras * version of this block on disk.
434d65f6f70SBen Gras *
435d65f6f70SBen Gras * And, it can't have changed underneath
436d65f6f70SBen Gras * us, because we have the segment lock.
437d65f6f70SBen Gras */
438d65f6f70SBen Gras error = copyin(blkp->bi_bp, bp->b_data, blkp->bi_size);
439d65f6f70SBen Gras if (error)
440d65f6f70SBen Gras goto err2;
441d65f6f70SBen Gras }
442d65f6f70SBen Gras }
443d65f6f70SBen Gras if ((error = lfs_bwrite_ext(bp, BW_CLEAN)) != 0)
444d65f6f70SBen Gras goto err2;
445d65f6f70SBen Gras
446d65f6f70SBen Gras nblkwritten++;
447d65f6f70SBen Gras /*
448d65f6f70SBen Gras * XXX should account indirect blocks and ifile pages as well
449d65f6f70SBen Gras */
450*0a6a1f1dSLionel Sambuc if (nblkwritten + lfs_lblkno(fs, ninowritten * DINOSIZE(fs))
451d65f6f70SBen Gras > LFS_MARKV_MAX_BLOCKS) {
452d65f6f70SBen Gras DLOG((DLOG_CLEAN, "lfs_markv: writing %d blks %d inos\n",
453d65f6f70SBen Gras nblkwritten, ninowritten));
454d65f6f70SBen Gras lfs_segwrite(mntp, SEGM_CLEAN);
455d65f6f70SBen Gras nblkwritten = ninowritten = 0;
456d65f6f70SBen Gras }
457d65f6f70SBen Gras }
458d65f6f70SBen Gras
459d65f6f70SBen Gras /*
460d65f6f70SBen Gras * Finish the old file, if there was one
461d65f6f70SBen Gras */
462*0a6a1f1dSLionel Sambuc if (vp != NULL) {
463*0a6a1f1dSLionel Sambuc vput(vp);
464*0a6a1f1dSLionel Sambuc vp = NULL;
465d65f6f70SBen Gras numrefed--;
466d65f6f70SBen Gras }
467d65f6f70SBen Gras
468d65f6f70SBen Gras #ifdef DIAGNOSTIC
469d65f6f70SBen Gras if (numrefed != 0)
470d65f6f70SBen Gras panic("lfs_markv: numrefed=%d", numrefed);
471d65f6f70SBen Gras #endif
472d65f6f70SBen Gras DLOG((DLOG_CLEAN, "lfs_markv: writing %d blks %d inos (check point)\n",
473d65f6f70SBen Gras nblkwritten, ninowritten));
474d65f6f70SBen Gras
475d65f6f70SBen Gras /*
476d65f6f70SBen Gras * The last write has to be SEGM_SYNC, because of calling semantics.
477d65f6f70SBen Gras * It also has to be SEGM_CKP, because otherwise we could write
478d65f6f70SBen Gras * over the newly cleaned data contained in a checkpoint, and then
479d65f6f70SBen Gras * we'd be unhappy at recovery time.
480d65f6f70SBen Gras */
481d65f6f70SBen Gras lfs_segwrite(mntp, SEGM_CLEAN | SEGM_CKP | SEGM_SYNC);
482d65f6f70SBen Gras
483d65f6f70SBen Gras lfs_segunlock(fs);
484d65f6f70SBen Gras
485d65f6f70SBen Gras vfs_unbusy(mntp, false, NULL);
486d65f6f70SBen Gras if (error)
487d65f6f70SBen Gras return (error);
488d65f6f70SBen Gras else if (do_again)
489d65f6f70SBen Gras return EAGAIN;
490d65f6f70SBen Gras
491d65f6f70SBen Gras return 0;
492d65f6f70SBen Gras
493d65f6f70SBen Gras err2:
494d65f6f70SBen Gras DLOG((DLOG_CLEAN, "lfs_markv err2\n"));
495d65f6f70SBen Gras
496d65f6f70SBen Gras /*
497d65f6f70SBen Gras * XXX we're here because copyin() failed.
498d65f6f70SBen Gras * XXX it means that we can't trust the cleanerd. too bad.
499d65f6f70SBen Gras * XXX how can we recover from this?
500d65f6f70SBen Gras */
501d65f6f70SBen Gras
502d65f6f70SBen Gras err3:
503d65f6f70SBen Gras /*
504d65f6f70SBen Gras * XXX should do segwrite here anyway?
505d65f6f70SBen Gras */
506d65f6f70SBen Gras
507*0a6a1f1dSLionel Sambuc if (vp != NULL) {
508*0a6a1f1dSLionel Sambuc vput(vp);
509*0a6a1f1dSLionel Sambuc vp = NULL;
510d65f6f70SBen Gras --numrefed;
511d65f6f70SBen Gras }
512d65f6f70SBen Gras
513d65f6f70SBen Gras lfs_segunlock(fs);
514d65f6f70SBen Gras vfs_unbusy(mntp, false, NULL);
515d65f6f70SBen Gras #ifdef DIAGNOSTIC
516d65f6f70SBen Gras if (numrefed != 0)
517d65f6f70SBen Gras panic("lfs_markv: numrefed=%d", numrefed);
518d65f6f70SBen Gras #endif
519d65f6f70SBen Gras
520d65f6f70SBen Gras return (error);
521d65f6f70SBen Gras }
522d65f6f70SBen Gras
523d65f6f70SBen Gras /*
524d65f6f70SBen Gras * sys_lfs_bmapv:
525d65f6f70SBen Gras *
526d65f6f70SBen Gras * This will fill in the current disk address for arrays of blocks.
527d65f6f70SBen Gras *
528d65f6f70SBen Gras * 0 on success
529d65f6f70SBen Gras * -1/errno is return on error.
530d65f6f70SBen Gras */
531d65f6f70SBen Gras #ifdef USE_64BIT_SYSCALLS
532d65f6f70SBen Gras int
sys_lfs_bmapv(struct lwp * l,const struct sys_lfs_bmapv_args * uap,register_t * retval)533d65f6f70SBen Gras sys_lfs_bmapv(struct lwp *l, const struct sys_lfs_bmapv_args *uap, register_t *retval)
534d65f6f70SBen Gras {
535d65f6f70SBen Gras /* {
536d65f6f70SBen Gras syscallarg(fsid_t *) fsidp;
537d65f6f70SBen Gras syscallarg(struct block_info *) blkiov;
538d65f6f70SBen Gras syscallarg(int) blkcnt;
539d65f6f70SBen Gras } */
540d65f6f70SBen Gras BLOCK_INFO *blkiov;
541d65f6f70SBen Gras int blkcnt, error;
542d65f6f70SBen Gras fsid_t fsid;
543d65f6f70SBen Gras struct lfs *fs;
544d65f6f70SBen Gras struct mount *mntp;
545d65f6f70SBen Gras
546d65f6f70SBen Gras if ((error = copyin(SCARG(uap, fsidp), &fsid, sizeof(fsid_t))) != 0)
547d65f6f70SBen Gras return (error);
548d65f6f70SBen Gras
549d65f6f70SBen Gras if ((mntp = vfs_getvfs(&fsid)) == NULL)
550d65f6f70SBen Gras return (ENOENT);
55184d9c625SLionel Sambuc fs = VFSTOULFS(mntp)->um_lfs;
552d65f6f70SBen Gras
553d65f6f70SBen Gras blkcnt = SCARG(uap, blkcnt);
554d65f6f70SBen Gras if ((u_int) blkcnt > SIZE_T_MAX / sizeof(BLOCK_INFO))
555d65f6f70SBen Gras return (EINVAL);
556d65f6f70SBen Gras KERNEL_LOCK(1, NULL);
557d65f6f70SBen Gras blkiov = lfs_malloc(fs, blkcnt * sizeof(BLOCK_INFO), LFS_NB_BLKIOV);
558d65f6f70SBen Gras if ((error = copyin(SCARG(uap, blkiov), blkiov,
559d65f6f70SBen Gras blkcnt * sizeof(BLOCK_INFO))) != 0)
560d65f6f70SBen Gras goto out;
561d65f6f70SBen Gras
562d65f6f70SBen Gras if ((error = lfs_bmapv(p, &fsid, blkiov, blkcnt)) == 0)
563d65f6f70SBen Gras copyout(blkiov, SCARG(uap, blkiov),
564d65f6f70SBen Gras blkcnt * sizeof(BLOCK_INFO));
565d65f6f70SBen Gras out:
566d65f6f70SBen Gras lfs_free(fs, blkiov, LFS_NB_BLKIOV);
567d65f6f70SBen Gras KERNEL_UNLOCK_ONE(NULL);
568d65f6f70SBen Gras return error;
569d65f6f70SBen Gras }
570d65f6f70SBen Gras #else
571d65f6f70SBen Gras int
sys_lfs_bmapv(struct lwp * l,const struct sys_lfs_bmapv_args * uap,register_t * retval)572d65f6f70SBen Gras sys_lfs_bmapv(struct lwp *l, const struct sys_lfs_bmapv_args *uap, register_t *retval)
573d65f6f70SBen Gras {
574d65f6f70SBen Gras /* {
575d65f6f70SBen Gras syscallarg(fsid_t *) fsidp;
576d65f6f70SBen Gras syscallarg(struct block_info *) blkiov;
577d65f6f70SBen Gras syscallarg(int) blkcnt;
578d65f6f70SBen Gras } */
579d65f6f70SBen Gras BLOCK_INFO *blkiov;
580d65f6f70SBen Gras BLOCK_INFO_15 *blkiov15;
581d65f6f70SBen Gras int i, blkcnt, error;
582d65f6f70SBen Gras fsid_t fsid;
583d65f6f70SBen Gras struct lfs *fs;
584d65f6f70SBen Gras struct mount *mntp;
585d65f6f70SBen Gras
586d65f6f70SBen Gras if ((error = copyin(SCARG(uap, fsidp), &fsid, sizeof(fsid_t))) != 0)
587d65f6f70SBen Gras return (error);
588d65f6f70SBen Gras
589d65f6f70SBen Gras if ((mntp = vfs_getvfs(&fsid)) == NULL)
590d65f6f70SBen Gras return (ENOENT);
59184d9c625SLionel Sambuc fs = VFSTOULFS(mntp)->um_lfs;
592d65f6f70SBen Gras
593d65f6f70SBen Gras blkcnt = SCARG(uap, blkcnt);
594d65f6f70SBen Gras if ((size_t) blkcnt > SIZE_T_MAX / sizeof(BLOCK_INFO))
595d65f6f70SBen Gras return (EINVAL);
596d65f6f70SBen Gras KERNEL_LOCK(1, NULL);
597d65f6f70SBen Gras blkiov = lfs_malloc(fs, blkcnt * sizeof(BLOCK_INFO), LFS_NB_BLKIOV);
598d65f6f70SBen Gras blkiov15 = lfs_malloc(fs, blkcnt * sizeof(BLOCK_INFO_15), LFS_NB_BLKIOV);
599d65f6f70SBen Gras if ((error = copyin(SCARG(uap, blkiov), blkiov15,
600d65f6f70SBen Gras blkcnt * sizeof(BLOCK_INFO_15))) != 0)
601d65f6f70SBen Gras goto out;
602d65f6f70SBen Gras
603d65f6f70SBen Gras for (i = 0; i < blkcnt; i++) {
604d65f6f70SBen Gras blkiov[i].bi_inode = blkiov15[i].bi_inode;
605d65f6f70SBen Gras blkiov[i].bi_lbn = blkiov15[i].bi_lbn;
606d65f6f70SBen Gras blkiov[i].bi_daddr = blkiov15[i].bi_daddr;
607d65f6f70SBen Gras blkiov[i].bi_segcreate = blkiov15[i].bi_segcreate;
608d65f6f70SBen Gras blkiov[i].bi_version = blkiov15[i].bi_version;
609d65f6f70SBen Gras blkiov[i].bi_bp = blkiov15[i].bi_bp;
610d65f6f70SBen Gras blkiov[i].bi_size = blkiov15[i].bi_size;
611d65f6f70SBen Gras }
612d65f6f70SBen Gras
613*0a6a1f1dSLionel Sambuc if ((error = lfs_bmapv(l, &fsid, blkiov, blkcnt)) == 0) {
614d65f6f70SBen Gras for (i = 0; i < blkcnt; i++) {
615d65f6f70SBen Gras blkiov15[i].bi_inode = blkiov[i].bi_inode;
616d65f6f70SBen Gras blkiov15[i].bi_lbn = blkiov[i].bi_lbn;
617d65f6f70SBen Gras blkiov15[i].bi_daddr = blkiov[i].bi_daddr;
618d65f6f70SBen Gras blkiov15[i].bi_segcreate = blkiov[i].bi_segcreate;
619d65f6f70SBen Gras blkiov15[i].bi_version = blkiov[i].bi_version;
620d65f6f70SBen Gras blkiov15[i].bi_bp = blkiov[i].bi_bp;
621d65f6f70SBen Gras blkiov15[i].bi_size = blkiov[i].bi_size;
622d65f6f70SBen Gras }
623d65f6f70SBen Gras copyout(blkiov15, SCARG(uap, blkiov),
624d65f6f70SBen Gras blkcnt * sizeof(BLOCK_INFO_15));
625d65f6f70SBen Gras }
626d65f6f70SBen Gras out:
627d65f6f70SBen Gras lfs_free(fs, blkiov, LFS_NB_BLKIOV);
628d65f6f70SBen Gras lfs_free(fs, blkiov15, LFS_NB_BLKIOV);
629d65f6f70SBen Gras KERNEL_UNLOCK_ONE(NULL);
630d65f6f70SBen Gras return error;
631d65f6f70SBen Gras }
632d65f6f70SBen Gras #endif
633d65f6f70SBen Gras
634d65f6f70SBen Gras int
lfs_bmapv(struct lwp * l,fsid_t * fsidp,BLOCK_INFO * blkiov,int blkcnt)635*0a6a1f1dSLionel Sambuc lfs_bmapv(struct lwp *l, fsid_t *fsidp, BLOCK_INFO *blkiov, int blkcnt)
636d65f6f70SBen Gras {
637d65f6f70SBen Gras BLOCK_INFO *blkp;
638d65f6f70SBen Gras IFILE *ifp;
639d65f6f70SBen Gras struct buf *bp;
640d65f6f70SBen Gras struct inode *ip = NULL;
641d65f6f70SBen Gras struct lfs *fs;
642d65f6f70SBen Gras struct mount *mntp;
64384d9c625SLionel Sambuc struct ulfsmount *ump;
644d65f6f70SBen Gras struct vnode *vp;
645d65f6f70SBen Gras ino_t lastino;
646d65f6f70SBen Gras daddr_t v_daddr;
647d65f6f70SBen Gras int cnt, error;
648d65f6f70SBen Gras int numrefed = 0;
649d65f6f70SBen Gras
650*0a6a1f1dSLionel Sambuc error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_LFS,
651*0a6a1f1dSLionel Sambuc KAUTH_REQ_SYSTEM_LFS_BMAPV, NULL, NULL, NULL);
652*0a6a1f1dSLionel Sambuc if (error)
653*0a6a1f1dSLionel Sambuc return (error);
654d65f6f70SBen Gras
655d65f6f70SBen Gras if ((mntp = vfs_getvfs(fsidp)) == NULL)
656d65f6f70SBen Gras return (ENOENT);
657d65f6f70SBen Gras
65884d9c625SLionel Sambuc ump = VFSTOULFS(mntp);
659d65f6f70SBen Gras if ((error = vfs_busy(mntp, NULL)) != 0)
660d65f6f70SBen Gras return (error);
661d65f6f70SBen Gras
662*0a6a1f1dSLionel Sambuc if (ump->um_cleaner_thread == NULL)
663*0a6a1f1dSLionel Sambuc ump->um_cleaner_thread = curlwp;
664*0a6a1f1dSLionel Sambuc KASSERT(ump->um_cleaner_thread == curlwp);
665*0a6a1f1dSLionel Sambuc
666d65f6f70SBen Gras cnt = blkcnt;
667d65f6f70SBen Gras
66884d9c625SLionel Sambuc fs = VFSTOULFS(mntp)->um_lfs;
669d65f6f70SBen Gras
670d65f6f70SBen Gras error = 0;
671d65f6f70SBen Gras
672d65f6f70SBen Gras /* these were inside the initialization for the for loop */
673*0a6a1f1dSLionel Sambuc vp = NULL;
674d65f6f70SBen Gras v_daddr = LFS_UNUSED_DADDR;
675d65f6f70SBen Gras lastino = LFS_UNUSED_INUM;
676d65f6f70SBen Gras for (blkp = blkiov; cnt--; ++blkp)
677d65f6f70SBen Gras {
678d65f6f70SBen Gras /*
679d65f6f70SBen Gras * Get the IFILE entry (only once) and see if the file still
680d65f6f70SBen Gras * exists.
681d65f6f70SBen Gras */
682d65f6f70SBen Gras if (lastino != blkp->bi_inode) {
683d65f6f70SBen Gras /*
684*0a6a1f1dSLionel Sambuc * Finish the old file, if there was one.
685d65f6f70SBen Gras */
686*0a6a1f1dSLionel Sambuc if (vp != NULL) {
687*0a6a1f1dSLionel Sambuc vput(vp);
688*0a6a1f1dSLionel Sambuc vp = NULL;
689d65f6f70SBen Gras numrefed--;
690d65f6f70SBen Gras }
691d65f6f70SBen Gras
692d65f6f70SBen Gras /*
693d65f6f70SBen Gras * Start a new file
694d65f6f70SBen Gras */
695d65f6f70SBen Gras lastino = blkp->bi_inode;
696d65f6f70SBen Gras if (blkp->bi_inode == LFS_IFILE_INUM)
697*0a6a1f1dSLionel Sambuc v_daddr = lfs_sb_getidaddr(fs);
698d65f6f70SBen Gras else {
699d65f6f70SBen Gras LFS_IENTRY(ifp, fs, blkp->bi_inode, bp);
700*0a6a1f1dSLionel Sambuc v_daddr = lfs_if_getdaddr(fs, ifp);
701d65f6f70SBen Gras brelse(bp, 0);
702d65f6f70SBen Gras }
703d65f6f70SBen Gras if (v_daddr == LFS_UNUSED_DADDR) {
704d65f6f70SBen Gras blkp->bi_daddr = LFS_UNUSED_DADDR;
705d65f6f70SBen Gras continue;
706d65f6f70SBen Gras }
707*0a6a1f1dSLionel Sambuc error = lfs_fastvget(mntp, blkp->bi_inode, NULL,
708*0a6a1f1dSLionel Sambuc LK_SHARED, &vp);
709d65f6f70SBen Gras if (error) {
710*0a6a1f1dSLionel Sambuc DLOG((DLOG_CLEAN, "lfs_bmapv: lfs_fastvget ino"
711d65f6f70SBen Gras "%d failed with %d",
712d65f6f70SBen Gras blkp->bi_inode,error));
713*0a6a1f1dSLionel Sambuc KASSERT(vp == NULL);
714d65f6f70SBen Gras continue;
715d65f6f70SBen Gras } else {
716d65f6f70SBen Gras KASSERT(VOP_ISLOCKED(vp));
717d65f6f70SBen Gras numrefed++;
718d65f6f70SBen Gras }
719d65f6f70SBen Gras ip = VTOI(vp);
720*0a6a1f1dSLionel Sambuc } else if (vp == NULL) {
721d65f6f70SBen Gras /*
722d65f6f70SBen Gras * This can only happen if the vnode is dead.
723d65f6f70SBen Gras * Keep going. Note that we DO NOT set the
724d65f6f70SBen Gras * bi_addr to anything -- if we failed to get
725d65f6f70SBen Gras * the vnode, for example, we want to assume
726d65f6f70SBen Gras * conservatively that all of its blocks *are*
727d65f6f70SBen Gras * located in the segment in question.
728d65f6f70SBen Gras * lfs_markv will throw them out if we are
729d65f6f70SBen Gras * wrong.
730d65f6f70SBen Gras */
731d65f6f70SBen Gras continue;
732d65f6f70SBen Gras }
733d65f6f70SBen Gras
734d65f6f70SBen Gras /* Past this point we are guaranteed that vp, ip are valid. */
735d65f6f70SBen Gras
736d65f6f70SBen Gras if (blkp->bi_lbn == LFS_UNUSED_LBN) {
737d65f6f70SBen Gras /*
738d65f6f70SBen Gras * We just want the inode address, which is
739d65f6f70SBen Gras * conveniently in v_daddr.
740d65f6f70SBen Gras */
741d65f6f70SBen Gras blkp->bi_daddr = v_daddr;
742d65f6f70SBen Gras } else {
743d65f6f70SBen Gras daddr_t bi_daddr;
744d65f6f70SBen Gras
745d65f6f70SBen Gras error = VOP_BMAP(vp, blkp->bi_lbn, NULL,
746d65f6f70SBen Gras &bi_daddr, NULL);
747d65f6f70SBen Gras if (error)
748d65f6f70SBen Gras {
749d65f6f70SBen Gras blkp->bi_daddr = LFS_UNUSED_DADDR;
750d65f6f70SBen Gras continue;
751d65f6f70SBen Gras }
75284d9c625SLionel Sambuc blkp->bi_daddr = LFS_DBTOFSB(fs, bi_daddr);
753d65f6f70SBen Gras /* Fill in the block size, too */
754d65f6f70SBen Gras if (blkp->bi_lbn >= 0)
75584d9c625SLionel Sambuc blkp->bi_size = lfs_blksize(fs, ip, blkp->bi_lbn);
756d65f6f70SBen Gras else
757*0a6a1f1dSLionel Sambuc blkp->bi_size = lfs_sb_getbsize(fs);
758d65f6f70SBen Gras }
759d65f6f70SBen Gras }
760d65f6f70SBen Gras
761d65f6f70SBen Gras /*
762*0a6a1f1dSLionel Sambuc * Finish the old file, if there was one.
763d65f6f70SBen Gras */
764*0a6a1f1dSLionel Sambuc if (vp != NULL) {
765*0a6a1f1dSLionel Sambuc vput(vp);
766*0a6a1f1dSLionel Sambuc vp = NULL;
767d65f6f70SBen Gras numrefed--;
768d65f6f70SBen Gras }
769d65f6f70SBen Gras
770d65f6f70SBen Gras #ifdef DIAGNOSTIC
771d65f6f70SBen Gras if (numrefed != 0)
772d65f6f70SBen Gras panic("lfs_bmapv: numrefed=%d", numrefed);
773d65f6f70SBen Gras #endif
774d65f6f70SBen Gras
775d65f6f70SBen Gras vfs_unbusy(mntp, false, NULL);
776d65f6f70SBen Gras
777d65f6f70SBen Gras return 0;
778d65f6f70SBen Gras }
779d65f6f70SBen Gras
780d65f6f70SBen Gras /*
781d65f6f70SBen Gras * sys_lfs_segclean:
782d65f6f70SBen Gras *
783d65f6f70SBen Gras * Mark the segment clean.
784d65f6f70SBen Gras *
785d65f6f70SBen Gras * 0 on success
786d65f6f70SBen Gras * -1/errno is return on error.
787d65f6f70SBen Gras */
788d65f6f70SBen Gras int
sys_lfs_segclean(struct lwp * l,const struct sys_lfs_segclean_args * uap,register_t * retval)789d65f6f70SBen Gras sys_lfs_segclean(struct lwp *l, const struct sys_lfs_segclean_args *uap, register_t *retval)
790d65f6f70SBen Gras {
791d65f6f70SBen Gras /* {
792d65f6f70SBen Gras syscallarg(fsid_t *) fsidp;
793d65f6f70SBen Gras syscallarg(u_long) segment;
794d65f6f70SBen Gras } */
795d65f6f70SBen Gras struct lfs *fs;
796d65f6f70SBen Gras struct mount *mntp;
797d65f6f70SBen Gras fsid_t fsid;
798d65f6f70SBen Gras int error;
799d65f6f70SBen Gras unsigned long segnum;
800d65f6f70SBen Gras
80184d9c625SLionel Sambuc error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_LFS,
80284d9c625SLionel Sambuc KAUTH_REQ_SYSTEM_LFS_SEGCLEAN, NULL, NULL, NULL);
80384d9c625SLionel Sambuc if (error)
804d65f6f70SBen Gras return (error);
805d65f6f70SBen Gras
806d65f6f70SBen Gras if ((error = copyin(SCARG(uap, fsidp), &fsid, sizeof(fsid_t))) != 0)
807d65f6f70SBen Gras return (error);
808d65f6f70SBen Gras if ((mntp = vfs_getvfs(&fsid)) == NULL)
809d65f6f70SBen Gras return (ENOENT);
810d65f6f70SBen Gras
81184d9c625SLionel Sambuc fs = VFSTOULFS(mntp)->um_lfs;
812d65f6f70SBen Gras segnum = SCARG(uap, segment);
813d65f6f70SBen Gras
814d65f6f70SBen Gras if ((error = vfs_busy(mntp, NULL)) != 0)
815d65f6f70SBen Gras return (error);
816d65f6f70SBen Gras
817d65f6f70SBen Gras KERNEL_LOCK(1, NULL);
818d65f6f70SBen Gras lfs_seglock(fs, SEGM_PROT);
819d65f6f70SBen Gras error = lfs_do_segclean(fs, segnum);
820d65f6f70SBen Gras lfs_segunlock(fs);
821d65f6f70SBen Gras KERNEL_UNLOCK_ONE(NULL);
822d65f6f70SBen Gras vfs_unbusy(mntp, false, NULL);
823d65f6f70SBen Gras return error;
824d65f6f70SBen Gras }
825d65f6f70SBen Gras
826d65f6f70SBen Gras /*
827d65f6f70SBen Gras * Actually mark the segment clean.
828d65f6f70SBen Gras * Must be called with the segment lock held.
829d65f6f70SBen Gras */
830d65f6f70SBen Gras int
lfs_do_segclean(struct lfs * fs,unsigned long segnum)831d65f6f70SBen Gras lfs_do_segclean(struct lfs *fs, unsigned long segnum)
832d65f6f70SBen Gras {
833d65f6f70SBen Gras extern int lfs_dostats;
834d65f6f70SBen Gras struct buf *bp;
835d65f6f70SBen Gras CLEANERINFO *cip;
836d65f6f70SBen Gras SEGUSE *sup;
837d65f6f70SBen Gras
838*0a6a1f1dSLionel Sambuc if (lfs_dtosn(fs, lfs_sb_getcurseg(fs)) == segnum) {
839d65f6f70SBen Gras return (EBUSY);
840d65f6f70SBen Gras }
841d65f6f70SBen Gras
842d65f6f70SBen Gras LFS_SEGENTRY(sup, fs, segnum, bp);
843d65f6f70SBen Gras if (sup->su_nbytes) {
844d65f6f70SBen Gras DLOG((DLOG_CLEAN, "lfs_segclean: not cleaning segment %lu:"
845d65f6f70SBen Gras " %d live bytes\n", segnum, sup->su_nbytes));
846d65f6f70SBen Gras brelse(bp, 0);
847d65f6f70SBen Gras return (EBUSY);
848d65f6f70SBen Gras }
849d65f6f70SBen Gras if (sup->su_flags & SEGUSE_ACTIVE) {
850d65f6f70SBen Gras DLOG((DLOG_CLEAN, "lfs_segclean: not cleaning segment %lu:"
851d65f6f70SBen Gras " segment is active\n", segnum));
852d65f6f70SBen Gras brelse(bp, 0);
853d65f6f70SBen Gras return (EBUSY);
854d65f6f70SBen Gras }
855d65f6f70SBen Gras if (!(sup->su_flags & SEGUSE_DIRTY)) {
856d65f6f70SBen Gras DLOG((DLOG_CLEAN, "lfs_segclean: not cleaning segment %lu:"
857d65f6f70SBen Gras " segment is already clean\n", segnum));
858d65f6f70SBen Gras brelse(bp, 0);
859d65f6f70SBen Gras return (EALREADY);
860d65f6f70SBen Gras }
861d65f6f70SBen Gras
862*0a6a1f1dSLionel Sambuc lfs_sb_addavail(fs, lfs_segtod(fs, 1));
863d65f6f70SBen Gras if (sup->su_flags & SEGUSE_SUPERBLOCK)
864*0a6a1f1dSLionel Sambuc lfs_sb_subavail(fs, lfs_btofsb(fs, LFS_SBPAD));
865*0a6a1f1dSLionel Sambuc if (lfs_sb_getversion(fs) > 1 && segnum == 0 &&
866*0a6a1f1dSLionel Sambuc lfs_sb_gets0addr(fs) < lfs_btofsb(fs, LFS_LABELPAD))
867*0a6a1f1dSLionel Sambuc lfs_sb_subavail(fs, lfs_btofsb(fs, LFS_LABELPAD) - lfs_sb_gets0addr(fs));
868d65f6f70SBen Gras mutex_enter(&lfs_lock);
869*0a6a1f1dSLionel Sambuc lfs_sb_addbfree(fs, sup->su_nsums * lfs_btofsb(fs, lfs_sb_getsumsize(fs)) +
870*0a6a1f1dSLionel Sambuc lfs_btofsb(fs, sup->su_ninos * lfs_sb_getibsize(fs)));
871*0a6a1f1dSLionel Sambuc lfs_sb_subdmeta(fs, sup->su_nsums * lfs_btofsb(fs, lfs_sb_getsumsize(fs)) +
872*0a6a1f1dSLionel Sambuc lfs_btofsb(fs, sup->su_ninos * lfs_sb_getibsize(fs)));
873*0a6a1f1dSLionel Sambuc if (lfs_sb_getdmeta(fs) < 0)
874*0a6a1f1dSLionel Sambuc lfs_sb_setdmeta(fs, 0);
875d65f6f70SBen Gras mutex_exit(&lfs_lock);
876d65f6f70SBen Gras sup->su_flags &= ~SEGUSE_DIRTY;
877d65f6f70SBen Gras LFS_WRITESEGENTRY(sup, fs, segnum, bp);
878d65f6f70SBen Gras
879d65f6f70SBen Gras LFS_CLEANERINFO(cip, fs, bp);
880*0a6a1f1dSLionel Sambuc lfs_ci_shiftdirtytoclean(fs, cip, 1);
881*0a6a1f1dSLionel Sambuc lfs_sb_setnclean(fs, lfs_ci_getclean(fs, cip));
882d65f6f70SBen Gras mutex_enter(&lfs_lock);
883*0a6a1f1dSLionel Sambuc lfs_ci_setbfree(fs, cip, lfs_sb_getbfree(fs));
884*0a6a1f1dSLionel Sambuc lfs_ci_setavail(fs, cip, lfs_sb_getavail(fs)
885*0a6a1f1dSLionel Sambuc - fs->lfs_ravail - fs->lfs_favail);
886*0a6a1f1dSLionel Sambuc wakeup(&fs->lfs_availsleep);
887d65f6f70SBen Gras mutex_exit(&lfs_lock);
888d65f6f70SBen Gras (void) LFS_BWRITE_LOG(bp);
889d65f6f70SBen Gras
890d65f6f70SBen Gras if (lfs_dostats)
891d65f6f70SBen Gras ++lfs_stats.segs_reclaimed;
892d65f6f70SBen Gras
893d65f6f70SBen Gras return (0);
894d65f6f70SBen Gras }
895d65f6f70SBen Gras
896d65f6f70SBen Gras /*
897d65f6f70SBen Gras * This will block until a segment in file system fsid is written. A timeout
898d65f6f70SBen Gras * in milliseconds may be specified which will awake the cleaner automatically.
899d65f6f70SBen Gras * An fsid of -1 means any file system, and a timeout of 0 means forever.
900d65f6f70SBen Gras */
901d65f6f70SBen Gras int
lfs_segwait(fsid_t * fsidp,struct timeval * tv)902d65f6f70SBen Gras lfs_segwait(fsid_t *fsidp, struct timeval *tv)
903d65f6f70SBen Gras {
904d65f6f70SBen Gras struct mount *mntp;
905d65f6f70SBen Gras void *addr;
906d65f6f70SBen Gras u_long timeout;
907d65f6f70SBen Gras int error;
908d65f6f70SBen Gras
909d65f6f70SBen Gras KERNEL_LOCK(1, NULL);
910d65f6f70SBen Gras if (fsidp == NULL || (mntp = vfs_getvfs(fsidp)) == NULL)
911d65f6f70SBen Gras addr = &lfs_allclean_wakeup;
912d65f6f70SBen Gras else
913*0a6a1f1dSLionel Sambuc addr = &VFSTOULFS(mntp)->um_lfs->lfs_nextsegsleep;
914d65f6f70SBen Gras /*
915d65f6f70SBen Gras * XXX THIS COULD SLEEP FOREVER IF TIMEOUT IS {0,0}!
916d65f6f70SBen Gras * XXX IS THAT WHAT IS INTENDED?
917d65f6f70SBen Gras */
918d65f6f70SBen Gras timeout = tvtohz(tv);
919d65f6f70SBen Gras error = tsleep(addr, PCATCH | PVFS, "segment", timeout);
920d65f6f70SBen Gras KERNEL_UNLOCK_ONE(NULL);
921d65f6f70SBen Gras return (error == ERESTART ? EINTR : 0);
922d65f6f70SBen Gras }
923d65f6f70SBen Gras
924d65f6f70SBen Gras /*
925d65f6f70SBen Gras * sys_lfs_segwait:
926d65f6f70SBen Gras *
927d65f6f70SBen Gras * System call wrapper around lfs_segwait().
928d65f6f70SBen Gras *
929d65f6f70SBen Gras * 0 on success
930d65f6f70SBen Gras * 1 on timeout
931d65f6f70SBen Gras * -1/errno is return on error.
932d65f6f70SBen Gras */
933d65f6f70SBen Gras int
sys___lfs_segwait50(struct lwp * l,const struct sys___lfs_segwait50_args * uap,register_t * retval)934d65f6f70SBen Gras sys___lfs_segwait50(struct lwp *l, const struct sys___lfs_segwait50_args *uap,
935d65f6f70SBen Gras register_t *retval)
936d65f6f70SBen Gras {
937d65f6f70SBen Gras /* {
938d65f6f70SBen Gras syscallarg(fsid_t *) fsidp;
939d65f6f70SBen Gras syscallarg(struct timeval *) tv;
940d65f6f70SBen Gras } */
941d65f6f70SBen Gras struct timeval atv;
942d65f6f70SBen Gras fsid_t fsid;
943d65f6f70SBen Gras int error;
944d65f6f70SBen Gras
945d65f6f70SBen Gras /* XXX need we be su to segwait? */
94684d9c625SLionel Sambuc error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_LFS,
94784d9c625SLionel Sambuc KAUTH_REQ_SYSTEM_LFS_SEGWAIT, NULL, NULL, NULL);
94884d9c625SLionel Sambuc if (error)
949d65f6f70SBen Gras return (error);
950d65f6f70SBen Gras if ((error = copyin(SCARG(uap, fsidp), &fsid, sizeof(fsid_t))) != 0)
951d65f6f70SBen Gras return (error);
952d65f6f70SBen Gras
953d65f6f70SBen Gras if (SCARG(uap, tv)) {
954d65f6f70SBen Gras error = copyin(SCARG(uap, tv), &atv, sizeof(struct timeval));
955d65f6f70SBen Gras if (error)
956d65f6f70SBen Gras return (error);
957d65f6f70SBen Gras if (itimerfix(&atv))
958d65f6f70SBen Gras return (EINVAL);
959d65f6f70SBen Gras } else /* NULL or invalid */
960d65f6f70SBen Gras atv.tv_sec = atv.tv_usec = 0;
961d65f6f70SBen Gras return lfs_segwait(&fsid, &atv);
962d65f6f70SBen Gras }
963d65f6f70SBen Gras
964d65f6f70SBen Gras /*
965*0a6a1f1dSLionel Sambuc * VFS_VGET call specialized for the cleaner. If the cleaner is
966d65f6f70SBen Gras * processing IINFO structures, it may have the ondisk inode already, so
967d65f6f70SBen Gras * don't go retrieving it again.
968d65f6f70SBen Gras *
969*0a6a1f1dSLionel Sambuc * Return the vnode referenced and locked.
970d65f6f70SBen Gras */
971d65f6f70SBen Gras
972*0a6a1f1dSLionel Sambuc static int
lfs_fastvget(struct mount * mp,ino_t ino,BLOCK_INFO * blkp,int lk_flags,struct vnode ** vpp)973*0a6a1f1dSLionel Sambuc lfs_fastvget(struct mount *mp, ino_t ino, BLOCK_INFO *blkp, int lk_flags,
974*0a6a1f1dSLionel Sambuc struct vnode **vpp)
975d65f6f70SBen Gras {
97684d9c625SLionel Sambuc struct ulfsmount *ump;
977*0a6a1f1dSLionel Sambuc int error;
978d65f6f70SBen Gras
97984d9c625SLionel Sambuc ump = VFSTOULFS(mp);
980*0a6a1f1dSLionel Sambuc ump->um_cleaner_hint = blkp;
981*0a6a1f1dSLionel Sambuc error = vcache_get(mp, &ino, sizeof(ino), vpp);
982*0a6a1f1dSLionel Sambuc ump->um_cleaner_hint = NULL;
983*0a6a1f1dSLionel Sambuc if (error)
984*0a6a1f1dSLionel Sambuc return error;
985*0a6a1f1dSLionel Sambuc error = vn_lock(*vpp, lk_flags);
986d65f6f70SBen Gras if (error) {
987*0a6a1f1dSLionel Sambuc if (error == EBUSY)
988*0a6a1f1dSLionel Sambuc error = EAGAIN;
989*0a6a1f1dSLionel Sambuc vrele(*vpp);
990d65f6f70SBen Gras *vpp = NULL;
991*0a6a1f1dSLionel Sambuc return error;
992d65f6f70SBen Gras }
993d65f6f70SBen Gras
994*0a6a1f1dSLionel Sambuc return 0;
995d65f6f70SBen Gras }
996d65f6f70SBen Gras
997d65f6f70SBen Gras /*
998d65f6f70SBen Gras * Make up a "fake" cleaner buffer, copy the data from userland into it.
999d65f6f70SBen Gras */
1000*0a6a1f1dSLionel Sambuc static struct buf *
lfs_fakebuf(struct lfs * fs,struct vnode * vp,daddr_t lbn,size_t size,void * uaddr)1001*0a6a1f1dSLionel Sambuc lfs_fakebuf(struct lfs *fs, struct vnode *vp, daddr_t lbn, size_t size, void *uaddr)
1002d65f6f70SBen Gras {
1003d65f6f70SBen Gras struct buf *bp;
1004d65f6f70SBen Gras int error;
1005d65f6f70SBen Gras
1006d65f6f70SBen Gras KASSERT(VTOI(vp)->i_number != LFS_IFILE_INUM);
1007d65f6f70SBen Gras
1008d65f6f70SBen Gras bp = lfs_newbuf(VTOI(vp)->i_lfs, vp, lbn, size, LFS_NB_CLEAN);
1009d65f6f70SBen Gras error = copyin(uaddr, bp->b_data, size);
1010d65f6f70SBen Gras if (error) {
1011d65f6f70SBen Gras lfs_freebuf(fs, bp);
1012d65f6f70SBen Gras return NULL;
1013d65f6f70SBen Gras }
1014d65f6f70SBen Gras KDASSERT(bp->b_iodone == lfs_callback);
1015d65f6f70SBen Gras
1016d65f6f70SBen Gras #if 0
1017d65f6f70SBen Gras mutex_enter(&lfs_lock);
1018d65f6f70SBen Gras ++fs->lfs_iocount;
1019d65f6f70SBen Gras mutex_exit(&lfs_lock);
1020d65f6f70SBen Gras #endif
1021d65f6f70SBen Gras bp->b_bufsize = size;
1022d65f6f70SBen Gras bp->b_bcount = size;
1023d65f6f70SBen Gras return (bp);
1024d65f6f70SBen Gras }
1025