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