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