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