xref: /original-bsd/sys/ufs/lfs/lfs_syscalls.c (revision ed5ac44c)
1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)lfs_syscalls.c	7.7 (Berkeley) 01/10/92
8  */
9 
10 #include <sys/param.h>
11 #include <sys/proc.h>
12 #include <sys/buf.h>
13 #include <sys/mount.h>
14 #include <sys/vnode.h>
15 #include <sys/malloc.h>
16 #include <sys/kernel.h>
17 
18 #include <ufs/ufs/quota.h>
19 #include <ufs/ufs/inode.h>
20 #include <ufs/ufs/ufsmount.h>
21 
22 #include <ufs/lfs/lfs.h>
23 #include <ufs/lfs/lfs_extern.h>
24 
25 /*
26  * lfs_markv:
27  *
28  * This will mark inodes and blocks dirty, so they are written into the log.
29  * It will block until all the blocks have been written.  The segment create
30  * time passed in the block_info and inode_info structures is used to decide
31  * if the data is valid for each block (in case some process dirtied a block
32  * or inode that is being cleaned between the determination that a block is
33  * live and the lfs_markv call).
34  *
35  *  0 on success
36  * -1/errno is return on error.
37  */
38 int
39 lfs_markv(p, uap, retval)
40 	struct proc *p;
41 	struct args {
42 		fsid_t fsid;		/* file system */
43 		BLOCK_INFO *blkiov;	/* block array */
44 		int blkcnt;		/* count of block array entries */
45 		INODE_INFO *inoiov;	/* inode array */
46 		int inocnt;		/* count of inode array entries */
47 	} *uap;
48 	int *retval;
49 {
50 	BLOCK_INFO *blkp;
51 	IFILE *ifp;
52 	INODE_INFO *inop;
53 	struct buf *bp;
54 	struct inode *ip;
55 	struct lfs *fs;
56 	struct mount *mntp;
57 	struct vnode *vp;
58 	void *start;
59 	ino_t lastino;
60 	daddr_t daddr;
61 	u_long bsize;
62 	int cnt, error;
63 
64 #ifdef VERBOSE
65 	printf("lfs_markv\n");
66 #endif
67 	if (error = suser(p->p_ucred, &p->p_acflag))
68 		return (error);
69 
70 	if ((mntp = getvfs(&uap->fsid)) == NULL)
71 		return (EINVAL);
72 
73 	cnt = uap->blkcnt;
74 	start = blkp = malloc(cnt * sizeof(BLOCK_INFO), M_SEGMENT, M_WAITOK);
75 	if (error = copyin(uap->blkiov, blkp, cnt * sizeof(BLOCK_INFO))) {
76 		free(blkp, M_SEGMENT);
77 		return (error);
78 	}
79 
80 	/*
81 	 * Mark blocks/inodes dirty.  Note that errors are mostly ignored.  If
82 	 * we can't get the info, the block is probably not all that useful,
83 	 * and hopefully subsequent calls from the cleaner will fix everything.
84 	 */
85 	fs = VFSTOUFS(mntp)->um_lfs;
86 	bsize = VFSTOUFS(mntp)->um_lfs->lfs_bsize;
87 	for (lastino = LFS_UNUSED_INUM; cnt--; ++blkp) {
88 		/*
89 		 * Get the IFILE entry (only once) and see if the file still
90 		 * exists.
91 		 */
92 		if (lastino != blkp->bi_inode) {
93 			lastino = blkp->bi_inode;
94 			LFS_IENTRY(ifp, fs, blkp->bi_inode, bp);
95 			daddr = ifp->if_daddr;
96 			brelse(bp);
97 			if (daddr == LFS_UNUSED_DADDR)
98 				continue;
99 		}
100 
101 		/*
102 		 * Get the vnode/inode.  If the inode modification time is
103 		 * earlier than the segment in which the block was found then
104 		 * they have to be valid, skip other checks.
105 		 */
106 		if (lfs_vget(mntp, blkp->bi_inode, &vp))
107 			continue;
108 		ip = VTOI(vp);
109 
110 		/*
111 		 * If modify time later than segment create time, see if the
112 		 * block has been replaced.
113 		 */
114 		if (ip->i_mtime > blkp->bi_segcreate &&
115 		    (lfs_bmap(vp, blkp->bi_lbn, NULL, &daddr) ||
116 		    daddr != blkp->bi_daddr)) {
117 			vput(vp);
118 			continue;
119 		}
120 
121 		/* Get the block (from core or the cleaner) and write it. */
122 		bp = getblk(vp, blkp->bi_lbn, bsize);
123 		vput(vp);
124 		if (!(bp->b_flags & B_CACHE) &&
125 		    (error = copyin(blkp->bi_bp, bp->b_un.b_daddr, bsize))) {
126 			brelse(bp);
127 			free(blkp, M_SEGMENT);
128 			return (error);
129 		}
130 		lfs_bwrite(bp);
131 	}
132 	free(start, M_SEGMENT);
133 
134 	cnt = uap->inocnt;
135 	start = inop = malloc(cnt * sizeof(INODE_INFO), M_SEGMENT, M_WAITOK);
136 	if (error = copyin(uap->inoiov, inop, cnt * sizeof(INODE_INFO))) {
137 		free(inop, M_SEGMENT);
138 		return (error);
139 	}
140 
141 	for (; cnt--; ++inop) {
142 		LFS_IENTRY(ifp, fs, inop->ii_inode, bp);
143 		daddr = ifp->if_daddr;
144 		brelse(bp);
145 		if (daddr != inop->ii_daddr)
146 			continue;
147 		/*
148 		 * XXX
149 		 * This is grossly inefficient since the cleaner just handed
150 		 * us a copy of the inode and we're going to have to seek
151 		 * to get our own.  The fix requires creating a version of
152 		 * lfs_vget that takes the copy and uses it instead of reading
153 		 * from disk, if it's not already in the cache.
154 		 */
155 		if (!lfs_vget(mntp, inop->ii_inode, &vp)) {
156 			VTOI(vp)->i_flag |= IMOD;
157 			vput(vp);
158 		}
159 	}
160 	free(start, M_SEGMENT);
161 	return (lfs_segwrite(mntp, 1));
162 }
163 
164 /*
165  * lfs_bmapv:
166  *
167  * This will fill in the current disk address for arrays of blocks.
168  *
169  *  0 on success
170  * -1/errno is return on error.
171  */
172 int
173 lfs_bmapv(p, uap, retval)
174 	struct proc *p;
175 	struct args {
176 		fsid_t fsid;		/* file system */
177 		BLOCK_INFO *blkiov;	/* block array */
178 		int blkcnt;		/* count of block array entries */
179 	} *uap;
180 	int *retval;
181 {
182 	BLOCK_INFO *blkp;
183 	struct mount *mntp;
184 	struct vnode *vp;
185 	void *start;
186 	daddr_t daddr;
187 	int cnt, error, step;
188 
189 #ifdef VERBOSE
190 	printf("lfs_bmapv\n");
191 #endif
192 	if (error = suser(p->p_ucred, &p->p_acflag))
193 		return (error);
194 
195 	if ((mntp = getvfs(&uap->fsid)) == NULL)
196 		return (EINVAL);
197 
198 	cnt = uap->blkcnt;
199 	start = blkp = malloc(cnt * sizeof(BLOCK_INFO), M_SEGMENT, M_WAITOK);
200 	if (error = copyin(uap->blkiov, blkp, cnt * sizeof(BLOCK_INFO))) {
201 		free(blkp, M_SEGMENT);
202 		return (error);
203 	}
204 
205 	for (step = cnt; step--; ++blkp) {
206 		if (lfs_vget(mntp, blkp->bi_inode, &vp))
207 			daddr = LFS_UNUSED_DADDR;
208 		else {
209 			if (lfs_bmap(vp, blkp->bi_lbn, NULL, &daddr))
210 				daddr = LFS_UNUSED_DADDR;
211 			vput(vp);
212 		}
213 		blkp->bi_daddr = daddr;
214         }
215 	copyout(start, uap->blkiov, cnt * sizeof(BLOCK_INFO));
216 	free(start, M_SEGMENT);
217 	return (0);
218 }
219 
220 /*
221  * lfs_segclean:
222  *
223  * Mark the segment clean.
224  *
225  *  0 on success
226  * -1/errno is return on error.
227  */
228 int
229 lfs_segclean(p, uap, retval)
230 	struct proc *p;
231 	struct args {
232 		fsid_t fsid;		/* file system */
233 		u_long segment;		/* segment number */
234 	} *uap;
235 	int *retval;
236 {
237 	CLEANERINFO *cip;
238 	SEGUSE *sup;
239 	struct buf *bp;
240 	struct mount *mntp;
241 	struct lfs *fs;
242 	int error;
243 
244 #ifdef VERBOSE
245 	printf("lfs_segclean\n");
246 #endif
247 	if (error = suser(p->p_ucred, &p->p_acflag))
248 		return (error);
249 
250 	if ((mntp = getvfs(&uap->fsid)) == NULL)
251 		return (EINVAL);
252 
253 	fs = VFSTOUFS(mntp)->um_lfs;
254 
255 	LFS_SEGENTRY(sup, fs, uap->segment, bp);
256 	sup->su_flags &= ~SEGUSE_DIRTY;
257 	sup->su_nbytes = 0;
258 	LFS_UBWRITE(bp);
259 
260 	LFS_CLEANERINFO(cip, fs, bp);
261 	++cip->clean;
262 	--cip->dirty;
263 	LFS_UBWRITE(bp);
264 
265 	return (0);
266 }
267 
268 /*
269  * lfs_segwait:
270  *
271  * This will block until a segment in file system fsid is written.  A timeout
272  * in milliseconds may be specified which will awake the cleaner automatically.
273  * An fsid of -1 means any file system, and a timeout of 0 means forever.
274  *
275  *  0 on success
276  *  1 on timeout
277  * -1/errno is return on error.
278  */
279 int
280 lfs_segwait(p, uap, retval)
281 	struct proc *p;
282 	struct args {
283 		fsid_t fsid;		/* file system */
284 		struct timeval *tv;	/* timeout */
285 	} *uap;
286 	int *retval;
287 {
288 	extern int lfs_allclean_wakeup;
289 	struct mount *mntp;
290 	struct timeval atv;
291 	void *addr;
292 	u_long timeout;
293 	int error, s;
294 
295 #ifdef VERBOSE
296 	printf("lfs_segwait\n");
297 #endif
298 	if (error = suser(p->p_ucred, &p->p_acflag))
299 		return (error);
300 
301 #ifdef WHEN_QUADS_WORK
302 	if (uap->fsid == (fsid_t)-1)
303 		addr = &lfs_allclean_wakeup;
304 	else {
305 		if ((mntp = getvfs(&uap->fsid)) == NULL)
306 			return (EINVAL);
307 		addr = &VFSTOUFS(mntp)->um_lfs->lfs_nextseg;
308 	}
309 #else
310 	if ((mntp = getvfs(&uap->fsid)) == NULL)
311 		addr = &lfs_allclean_wakeup;
312 	else
313 		addr = &VFSTOUFS(mntp)->um_lfs->lfs_nextseg;
314 #endif
315 
316 	if (uap->tv) {
317 		if (error = copyin(uap->tv, &atv, sizeof(struct timeval)))
318 			return (error);
319 		if (itimerfix(&atv))
320 			return (EINVAL);
321 		s = splhigh(); timevaladd(&atv, &time); splx(s);
322 		timeout = hzto(&atv);
323 	} else
324 		timeout = 0;
325 
326 	error = tsleep(addr, PCATCH | PUSER, "segment", timeout);
327 	return (error == ERESTART ? EINTR : 0);
328 }
329